diff options
author | Tor Norbye <tnorbye@google.com> | 2013-08-09 11:23:59 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-08-09 11:23:59 -0700 |
commit | 10605ee04b8297b2f9f2d90aa91d73bc669ce891 (patch) | |
tree | de8a2f44bdd9e0969b79431cfba64a9036d69681 | |
parent | 3361ba4955436eee16e16e1f0ae0c20c98d35c45 (diff) | |
parent | 9fdfa377b20b105e3a9907d32434787f75781c35 (diff) | |
download | idea-10605ee04b8297b2f9f2d90aa91d73bc669ce891.tar.gz |
Merge remote-tracking branch 'aosp/snapshot-master' into merge
212 files changed, 3565 insertions, 2468 deletions
diff --git a/.idea/modules.xml b/.idea/modules.xml index df12f9431029..8e79a973d919 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -151,7 +151,6 @@ <module fileurl="file://$PROJECT_DIR$/plugins/tasks/tasks-core/tasks-core.iml" filepath="$PROJECT_DIR$/plugins/tasks/tasks-core/tasks-core.iml" group="plugins/tasks" /> <module fileurl="file://$PROJECT_DIR$/plugins/tasks/tasks-java/tasks-java.iml" filepath="$PROJECT_DIR$/plugins/tasks/tasks-java/tasks-java.iml" group="plugins/tasks" /> <module fileurl="file://$PROJECT_DIR$/plugins/tasks/tasks-tests/tasks-tests.iml" filepath="$PROJECT_DIR$/plugins/tasks/tasks-tests/tasks-tests.iml" group="plugins/tasks" /> - <module fileurl="file://$PROJECT_DIR$/plugins/tasks/tasks-time-tracking/tasks-time-tracking.iml" filepath="$PROJECT_DIR$/plugins/tasks/tasks-time-tracking/tasks-time-tracking.iml" group="plugins/tasks" /> <module fileurl="file://$PROJECT_DIR$/plugins/terminal/terminal.iml" filepath="$PROJECT_DIR$/plugins/terminal/terminal.iml" group="plugins" /> <module fileurl="file://$PROJECT_DIR$/platform/testFramework/testFramework.iml" filepath="$PROJECT_DIR$/platform/testFramework/testFramework.iml" group="platform" /> <module fileurl="file://$PROJECT_DIR$/java/testFramework/testFramework-java.iml" filepath="$PROJECT_DIR$/java/testFramework/testFramework-java.iml" group="java" /> diff --git a/.idea/runConfigurations/IDEA.xml b/.idea/runConfigurations/IDEA.xml index f8e1c1f854d0..d201d0a92bd1 100644 --- a/.idea/runConfigurations/IDEA.xml +++ b/.idea/runConfigurations/IDEA.xml @@ -18,9 +18,7 @@ <option name="TRANSPORT" value="0" /> <option name="LOCAL" value="true" /> </RunnerSettings> - <RunnerSettings RunnerId="Profile "> - <option name="myExternalizedOptions" value=" additional-options= snapshots-dir= " /> - </RunnerSettings> + <RunnerSettings RunnerId="Profile " /> <RunnerSettings RunnerId="Run" /> <ConfigurationWrapper RunnerId="Debug" /> <ConfigurationWrapper RunnerId="Run" /> diff --git a/bin/win/jumplistbridge.dll b/bin/win/jumplistbridge.dll Binary files differnew file mode 100644 index 000000000000..611dd62b41d4 --- /dev/null +++ b/bin/win/jumplistbridge.dll diff --git a/bin/win/jumplistbridge64.dll b/bin/win/jumplistbridge64.dll Binary files differnew file mode 100644 index 000000000000..fad8c52f521f --- /dev/null +++ b/bin/win/jumplistbridge64.dll diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index c6b526f85d73..c099600da480 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -260,7 +260,7 @@ libraryLicense(name: "asm-4.0-all", libraryName: "asm-4.0-all", version: "4.0", libraryLicense(name: "jsr305", libraryName: "jsr305", version: "snapshot", license: "BSD", url: "http://code.google.com/p/jsr-305/", licenseUrl: "http://code.google.com/p/jsr-305/source/browse/trunk/ri/LICENSE") libraryLicense(name: "jzlib", libraryName: "jzlib", version: "1.1.1", license: "BSD", url: "http://www.jcraft.com/jzlib/", licenseUrl: "http://www.jcraft.com/jzlib/LICENSE.txt") libraryLicense(name: "PureJavaComm", libraryName: "purejavacomm", version: "0.0.16", license: "BSD", url: "http://www.sparetimelabs.com/purejavacomm") -libraryLicense(name: "JPty", libraryName: "jpty", version: "git snapshot", license: "Apache 2.0", url: "https://github.com/jawi/JPty") +libraryLicense(name: "pty4j", libraryName: "pty4j", version: "0.2", license: "Eclipse Public License v1.0", url: "https://github.com/traff/pty4j") libraryLicense(name: "JediTerm", libraryName: "jediterm-pty", version: "0.2", license: "LGPL 2", url: "https://github.com/traff/jediterm", licenseUrl: "https://github.com/traff/jediterm/blob/master/COPYING") libraryLicense(name: "bouncy-castle", version: "1.48", license: "MIT License", url: "http://bouncycastle.org", licenseUrl: "http://bouncycastle.org/licence.html") libraryLicense(name: "kXML2", libraryName: "kxml2", version: "2.3.0", license: "BSD", url: "http://sourceforge.net/projects/kxml/") diff --git a/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java b/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java index e0698ed140b1..ef0e14aa4515 100644 --- a/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java +++ b/images/src/org/intellij/images/fileTypes/ImageDocumentationProvider.java @@ -43,6 +43,7 @@ public class ImageDocumentationProvider extends AbstractDocumentationProvider { final VirtualFile file = ((PsiFileSystemItem)element).getVirtualFile(); if (file instanceof VirtualFileWithId && !DumbService.isDumb(element.getProject())) { ImageInfoIndex.processValues(file, new FileBasedIndex.ValueProcessor<ImageInfoIndex.ImageInfo>() { + @Override public boolean process(VirtualFile file, ImageInfoIndex.ImageInfo value) { int imageWidth = value.width; int imageHeight = value.height; @@ -62,7 +63,7 @@ public class ImageDocumentationProvider extends AbstractDocumentationProvider { result[0] = String.format("<html><body><img src=\"%s\" width=\"%s\" height=\"%s\"><p>%sx%s, %sbpp</p><body></html>", url, imageWidth, imageHeight, value.width, value.height, value.bpp); } - catch (URISyntaxException e) { + catch (URISyntaxException ignored) { // nothing } return true; diff --git a/java/execution/impl/src/com/intellij/execution/junit2/segments/Extractor.java b/java/execution/impl/src/com/intellij/execution/junit2/segments/Extractor.java index 0cb5b117817c..508f8e6ecb14 100644 --- a/java/execution/impl/src/com/intellij/execution/junit2/segments/Extractor.java +++ b/java/execution/impl/src/com/intellij/execution/junit2/segments/Extractor.java @@ -63,7 +63,7 @@ public class Extractor implements Disposable { myFulfilledWorkGate.setDispactchListener(listener); } - public void setPacketDispatcher(final PacketProcessor packetProcessor, final DeferredActionsQueue queue) { + public void setPacketDispatcher(@NotNull final PacketProcessor packetProcessor, final DeferredActionsQueue queue) { myFulfilledWorkGate = new DeferredActionsQueue() { //todo make it all later @Override public void addLast(final Runnable runnable) { @@ -111,7 +111,7 @@ public class Extractor implements Disposable { public void addRequest(Runnable runnable, final DeferredActionsQueue queue) { myQueue.queue(new MyUpdate(runnable, queue, myOrder.incrementAndGet())); } - + private static class MyUpdate extends Update { private final Runnable myRunnable; private final DeferredActionsQueue myQueue; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index d927d8cb78a4..bf0fc63be2a2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1485,7 +1485,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { return Collections.emptyList(); } - private static List<MethodContract> parseContract(String text) throws ParseException { + public static List<MethodContract> parseContract(String text) throws ParseException { List<MethodContract> result = ContainerUtil.newArrayList(); for (String clause : StringUtil.replace(text, " ", "").split(";")) { String arrow = "->"; @@ -1516,7 +1516,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { throw new ParseException("Constraint should be one of: null, !null, true, false, exit, fail, _. Found: " + name); } - private static class ParseException extends Exception { + public static class ParseException extends Exception { private ParseException(String message) { super(message); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index fc58969f5122..7edeb3ac30b7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -48,6 +48,7 @@ import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; import org.jdom.Element; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -98,6 +99,35 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { public void visitClassInitializer(PsiClassInitializer initializer) { analyzeCodeBlock(initializer.getBody(), holder); } + + @Override + public void visitAnnotation(PsiAnnotation annotation) { + if (!Contract.class.getName().equals(annotation.getQualifiedName())) return; + + PsiMethod method = PsiTreeUtil.getParentOfType(annotation, PsiMethod.class); + if (method == null) return; + + PsiAnnotationMemberValue value = annotation.findAttributeValue(null); + Object text = JavaPsiFacade.getInstance(annotation.getProject()).getConstantEvaluationHelper().computeConstantExpression(value); + if (!(text instanceof String)) return; + + List<MethodContract> contracts; + try { + contracts = ControlFlowAnalyzer.parseContract((String)text); + } + catch (ControlFlowAnalyzer.ParseException e) { + holder.registerProblem(value, e.getMessage()); + return; + } + int paramCount = method.getParameterList().getParametersCount(); + for (int i = 0; i < contracts.size(); i++) { + MethodContract contract = contracts.get(i); + if (contract.arguments.length != paramCount) { + holder.registerProblem(value, "Method takes " + paramCount + " parameters, while contract clause " + i + " expects " + contract.arguments.length); + return; + } + } + } }; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java index 87e99c553b36..d552212d0243 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyInspection.java @@ -37,6 +37,7 @@ public class UnnecessaryModuleDependencyInspection extends GlobalInspectionTool if (refEntity instanceof RefModule){ final RefModule refModule = (RefModule)refEntity; final Module module = refModule.getModule(); + if (module.isDisposed()) return CommonProblemDescriptor.EMPTY_ARRAY; final Module[] declaredDependencies = ModuleRootManager.getInstance(module).getDependencies(); List<CommonProblemDescriptor> descriptors = new ArrayList<CommonProblemDescriptor>(); final Set<Module> modules = refModule.getUserData(UnnecessaryModuleDependencyAnnotator.DEPENDENCIES); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 55990a6ffd0f..d0aa4f960005 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -1275,22 +1275,22 @@ public class GenericsHighlightUtil { public static HighlightInfo checkCannotPassInner(PsiJavaCodeReferenceElement ref) { if (ref.getParent() instanceof PsiTypeElement) { final PsiClass psiClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class); - if (psiClass != null) { - if (PsiTreeUtil.isAncestor(psiClass.getExtendsList(), ref, false) || - PsiTreeUtil.isAncestor(psiClass.getImplementsList(), ref, false)) { - final PsiElement qualifier = ref.getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() == psiClass) { - final PsiElement resolve = ref.resolve(); - if (resolve instanceof PsiClass) { - final PsiClass containingClass = ((PsiClass)resolve).getContainingClass(); - if (containingClass != null) { - if (psiClass.isInheritor(containingClass, true) || - unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getExtendsList()) || - unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getImplementsList())) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create(); - } - } - } + if (psiClass == null) return null; + if (PsiTreeUtil.isAncestor(psiClass.getExtendsList(), ref, false) || + PsiTreeUtil.isAncestor(psiClass.getImplementsList(), ref, false)) { + final PsiElement qualifier = ref.getQualifier(); + if (qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() == psiClass) { + final PsiJavaCodeReferenceElement referenceElement = PsiTreeUtil.getParentOfType(ref, PsiJavaCodeReferenceElement.class); + if (referenceElement == null) return null; + final PsiElement typeClass = referenceElement.resolve(); + if (!(typeClass instanceof PsiClass)) return null; + final PsiElement resolve = ref.resolve(); + final PsiClass containingClass = resolve != null ? ((PsiClass)resolve).getContainingClass() : null; + if (containingClass == null) return null; + if (psiClass.isInheritor(containingClass, true) || + unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass)typeClass, ((PsiClass)resolve).getExtendsList()) || + unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance((PsiClass)typeClass, ((PsiClass)resolve).getImplementsList())) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create(); } } } @@ -1306,7 +1306,7 @@ public class GenericsHighlightUtil { final PsiElement superClass = referenceElement.resolve(); if (superClass instanceof PsiClass) { final PsiClass superContainingClass = ((PsiClass)superClass).getContainingClass(); - if (superContainingClass != null && containingClass.isInheritor(superContainingClass, true)) { + if (superContainingClass != null && InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true)) { return true; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java index 5e632738fa5c..eae38cc03a17 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java @@ -72,7 +72,9 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle if (editor == null || !FileModificationService.getInstance().prepareFileForWrite(myPsiElement.getContainingFile())) return; if (myPsiElement instanceof PsiEnumConstant) { - final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass(), true); + final boolean hasClassInitializer = ((PsiEnumConstant)myPsiElement).getInitializingClass() != null; + final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, + ((PsiEnumConstant)myPsiElement).getContainingClass(), hasClassInitializer); if (chooser == null) return; final List<PsiMethodMember> selectedElements = chooser.getSelectedElements(); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/MemberImplementorExplorersProviderImpl.java b/java/java-impl/src/com/intellij/codeInsight/generation/MemberImplementorExplorersProviderImpl.java new file mode 100644 index 000000000000..704115d2a793 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/MemberImplementorExplorersProviderImpl.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.generation; + +import com.intellij.codeInsight.MemberImplementorExplorer; + +public class MemberImplementorExplorersProviderImpl implements OverrideImplementExploreUtil.MemberImplementorExplorersProvider { + @Override + public MemberImplementorExplorer[] getExplorers() { + return OverrideImplementUtil.getImplementors(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/internal/UndesirableClassUsageInspection.java b/java/java-impl/src/com/intellij/codeInspection/internal/UndesirableClassUsageInspection.java index 5a0741536f17..bf463e271d8e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/internal/UndesirableClassUsageInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/internal/UndesirableClassUsageInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.intellij.codeInspection.internal; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.application.QueryExecutorBase; +import com.intellij.openapi.ui.ComboBox; import com.intellij.psi.*; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; @@ -38,6 +39,7 @@ public class UndesirableClassUsageInspection extends InternalInspection { CLASSES.put(JTable.class.getName(), JBTable.class.getName()); CLASSES.put(JTree.class.getName(), Tree.class.getName()); CLASSES.put(JScrollPane.class.getName(), JBScrollPane.class.getName()); + CLASSES.put(JComboBox.class.getName(), ComboBox.class.getName()); CLASSES.put(QueryExecutor.class.getName(), QueryExecutorBase.class.getName()); CLASSES.put(BufferedImage.class.getName(), "UIUtil.createImage()"); } diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java index 83da82862c22..e8c5ebc9a771 100644 --- a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java @@ -3,13 +3,11 @@ package com.intellij.compilerOutputIndex.api.indexer; import com.intellij.compilerOutputIndex.api.fs.CompilerOutputFilesUtil; import com.intellij.compilerOutputIndex.api.fs.FileVisitorService; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.CompileContext; -import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilationStatusAdapter; import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -19,6 +17,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.openapi.util.registry.RegistryValueListener; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Consumer; import com.intellij.util.indexing.ID; import com.intellij.util.indexing.IndexInfrastructure; @@ -111,39 +110,22 @@ public class CompilerOutputIndexer extends AbstractProjectComponent { catch (IOException e) { throw new RuntimeException(e); } - CompilerManager.getInstance(myProject).addAfterTask(new CompileTask() { + CompilerManager.getInstance(myProject).addCompilationStatusListener(new CompilationStatusAdapter() { @Override - public boolean execute(final CompileContext context) { - if (myEnabled.get() && myInProgress.compareAndSet(false, true)) { - myLock.lock(); + public void fileGenerated(final String outputRoot, final String relativePath) { + if (myEnabled.get() && StringUtil.endsWith(relativePath, CompilerOutputFilesUtil.CLASS_FILES_SUFFIX)) { try { - context.getProgressIndicator().setText("Compiler output indexing in progress"); - final Consumer<File> fileConsumer = new Consumer<File>() { - @Override - public void consume(final File file) { - try { - doIndexing(file, context.getProgressIndicator()); - } - catch (ProcessCanceledException e0) { - throw e0; - } - catch (RuntimeException e) { - LOG.error(e); - } - } - }; - for (final Module module : context.getCompileScope().getAffectedModules()) { - CompilerOutputFilesUtil.iterateModuleClassFiles(module, fileConsumer); - } + doIndexing(new File(outputRoot, relativePath), null); } - finally { - myLock.unlock(); - myInProgress.set(false); + catch (ProcessCanceledException e0) { + throw e0; + } + catch (RuntimeException e) { + LOG.error(e); } } - return true; } - }); + }, myProject); if (needReindex) { reindexAllProjectInBackground(); } @@ -233,7 +215,7 @@ public class CompilerOutputIndexer extends AbstractProjectComponent { } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - private void doIndexing(@NotNull final File file, @NotNull final ProgressIndicator indicator) { + private void doIndexing(@NotNull final File file, @Nullable final ProgressIndicator indicator) { final String filePath; try { filePath = file.getCanonicalPath(); @@ -267,7 +249,9 @@ public class CompilerOutputIndexer extends AbstractProjectComponent { } } try { - indicator.setText2(filePath); + if (indicator != null) { + indicator.setText2(filePath); + } final int id = myFileEnumerator.enumerate(filePath); for (final CompilerOutputBaseIndex index : myIndexes) { index.update(id, reader); diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java index e8197bbefb47..570e42e58f34 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java @@ -125,7 +125,7 @@ public class ClassesTreeStructureProvider implements SelectableTreeStructureProv return current != null ? current : baseRootFile; } - private boolean isSelectable(PsiElement element) { + private static boolean isSelectable(PsiElement element) { if (element instanceof PsiFileSystemItem) return true; if (element instanceof PsiField || element instanceof PsiClass || element instanceof PsiMethod) { diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java index 5ab99de764ed..ac8de81cf0f0 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java @@ -84,7 +84,7 @@ public class JavaCodeBlockModificationListener implements PsiTreeChangePreproces myModificationTracker.incCounter(); } } - catch (PsiInvalidElementAccessException e) { + catch (PsiInvalidElementAccessException ignored) { myModificationTracker.incCounter(); // Shall not happen actually, just a pre-release paranoia } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java index 604b90e896d6..c23cf728f500 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java @@ -16,7 +16,7 @@ package com.intellij.psi.impl.source.resolve.reference.impl.providers; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; @@ -87,7 +87,7 @@ public class FilePathReferenceProvider extends PsiReferenceProvider { systemItems.addAll(getRoots(forModule, true)); } } else { - systemItems.addAll(getRoots(ModuleUtil.findModuleForPsiElement(getElement()), true)); + systemItems.addAll(getRoots(ModuleUtilCore.findModuleForPsiElement(getElement()), true)); } return systemItems; } @@ -144,7 +144,7 @@ public class FilePathReferenceProvider extends PsiReferenceProvider { if (thisModule == null) return Collections.emptyList(); Set<Module> modules = new com.intellij.util.containers.HashSet<Module>(); ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(thisModule); - ModuleUtil.getDependencies(thisModule, modules); + ModuleUtilCore.getDependencies(thisModule, modules); List<PsiFileSystemItem> result = new ArrayList<PsiFileSystemItem>(); final PsiManager psiManager = PsiManager.getInstance(thisModule.getProject()); if (includingClasses) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java index 7d70ee9f2cb3..59e311a213a2 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/injected/JavaConcatenationInjectorManager.java @@ -215,7 +215,7 @@ public class JavaConcatenationInjectorManager implements ModificationTracker { private static final List<Class<PsiLiteralExpression>> LITERALS = Arrays.asList(PsiLiteralExpression.class); } - private final List<ConcatenationAwareInjector> myConcatenationInjectors = ContainerUtil.createEmptyCOWList(); + private final List<ConcatenationAwareInjector> myConcatenationInjectors = ContainerUtil.createLockFreeCopyOnWriteList(); public void registerConcatenationInjector(@NotNull ConcatenationAwareInjector injector) { myConcatenationInjectors.add(injector); concatenationInjectorsChanged(); diff --git a/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java b/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java index 05207ff007fa..d60d08d926e8 100644 --- a/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java +++ b/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java @@ -153,7 +153,7 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction { PsiMethod method = generateDummyMethod(editor, file); if (method == null) return; - TestIntegrationUtils.runTestMethodTemplate(myMethodKind, framework, editor, targetClass, method, "name", false); + TestIntegrationUtils.runTestMethodTemplate(myMethodKind, framework, editor, targetClass, method, "name", false, null); } catch (IncorrectOperationException e) { HintManager.getInstance().showErrorHint(editor, "Cannot generate method: " + e.getMessage()); diff --git a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java index ea22f86b5268..fd8d812058e0 100644 --- a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java +++ b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java @@ -41,10 +41,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Properties; +import java.util.*; public class TestIntegrationUtils { private static final Logger LOG = Logger.getInstance("#" + TestIntegrationUtils.class.getName()); @@ -139,8 +136,8 @@ public class TestIntegrationUtils { final PsiClass targetClass, final PsiMethod method, @Nullable String name, - boolean automatic) { - Template template = createTestMethodTemplate(methodKind, framework, targetClass, name, automatic); + boolean automatic, Set<String> existingNames) { + Template template = createTestMethodTemplate(methodKind, framework, targetClass, name, automatic, existingNames); final TextRange range = method.getTextRange(); editor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), ""); @@ -182,7 +179,8 @@ public class TestIntegrationUtils { TestFramework descriptor, PsiClass targetClass, @Nullable String name, - boolean automatic) { + boolean automatic, + Set<String> existingNames) { FileTemplateDescriptor templateDesc = methodKind.getFileTemplateDescriptor(descriptor); String templateName = templateDesc.getFileName(); FileTemplate fileTemplate = FileTemplateManager.getInstance().getCodeTemplate(templateName); @@ -199,6 +197,17 @@ public class TestIntegrationUtils { if (name == null) name = methodKind.getDefaultName(); + if (existingNames != null && !existingNames.add(name)) { + int idx = 1; + while (existingNames.contains(name)) { + final String newName = name + (idx++); + if (existingNames.add(newName)) { + name = newName; + break; + } + } + } + templateText = StringUtil.replace(templateText, "${BODY}", ""); int from = 0; diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java index 4fdb9a450e07..a23c6cadfe64 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/JavaTestGenerator.java @@ -33,6 +33,8 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; public class JavaTestGenerator implements TestGenerator { public JavaTestGenerator() { @@ -96,14 +98,15 @@ public class JavaTestGenerator implements TestGenerator { Collection<MemberInfo> methods, boolean generateBefore, boolean generateAfter) throws IncorrectOperationException { + final Set<String> existingNames = new HashSet<String>(); if (generateBefore) { - generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null); + generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null, existingNames); } if (generateAfter) { - generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null); + generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null, existingNames); } for (MemberInfo m : methods) { - generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName()); + generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName(), existingNames); } } @@ -121,10 +124,10 @@ public class JavaTestGenerator implements TestGenerator { TestFramework descriptor, PsiClass targetClass, Editor editor, - @Nullable String name) { + @Nullable String name, Set<String> existingNames) { PsiMethod method = (PsiMethod)targetClass.add(TestIntegrationUtils.createDummyMethod(targetClass)); PsiDocumentManager.getInstance(targetClass.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true); + TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true, existingNames); } @Override diff --git a/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java b/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java index 8a2ed8be9d12..da53cb27bb92 100644 --- a/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java +++ b/java/java-impl/src/com/intellij/util/xml/PsiClassConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -122,8 +122,6 @@ public class PsiClassConverter extends Converter<PsiClass> implements CustomRefe extendClass); provider.setOption(JavaClassReferenceProvider.CLASS_KIND, ClassKind.ANNOTATION); - //provider.setOption(JavaClassReferenceProvider.EXTEND_CLASS_NAMES, new String[] {"org.springframework.samples.petclinic.jsr330.Foo"}); - // return provider; } } diff --git a/java/java-psi-api/src/com/intellij/codeInsight/MemberImplementorExplorer.java b/java/java-psi-api/src/com/intellij/codeInsight/MemberImplementorExplorer.java index 55b3c493db7c..288b81238854 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/MemberImplementorExplorer.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/MemberImplementorExplorer.java @@ -1,13 +1,9 @@ package com.intellij.codeInsight; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import org.jetbrains.annotations.NotNull; public interface MemberImplementorExplorer { - ExtensionPointName<MemberImplementorExplorer> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.methodImplementor"); - - @NotNull - PsiMethod[] getMethodsToImplement(PsiClass aClass); + @NotNull PsiMethod[] getMethodsToImplement(PsiClass aClass); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiConstantEvaluationHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiConstantEvaluationHelper.java index 3c377f7da610..290d1bf11b70 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiConstantEvaluationHelper.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiConstantEvaluationHelper.java @@ -15,6 +15,7 @@ */ package com.intellij.psi; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import java.util.concurrent.ConcurrentMap; @@ -33,6 +34,7 @@ public abstract class PsiConstantEvaluationHelper { * @return the result of the evaluation, or null if the expression is not a constant expression. */ @Nullable + @Contract("null -> null") public Object computeConstantExpression(PsiElement expression) { return computeConstantExpression(expression, false); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index b7d32ac58130..66cb12fad3ed 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -734,15 +734,12 @@ public final class PsiUtil extends PsiUtilCore { if (!allowPublicAbstract && aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !aClass.isEnum()) { modifier = PsiModifier.PROTECTED; } - else if (aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { + else if (aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || aClass.isEnum()) { modifier = PsiModifier.PACKAGE_LOCAL; } else if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) { modifier = PsiModifier.PRIVATE; } - else if (aClass.isEnum()) { - modifier = PsiModifier.PRIVATE; - } return modifier; } diff --git a/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java index 373e5befe7c7..7ee8b1d296e7 100644 --- a/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java +++ b/java/java-psi-api/src/com/intellij/util/VisibilityUtil.java @@ -50,13 +50,7 @@ public class VisibilityUtil { @PsiModifier.ModifierConstant public static String getHighestVisibility(@PsiModifier.ModifierConstant String v1, @PsiModifier.ModifierConstant String v2) { - if(v1.equals(v2)) return v1; - - if(PsiModifier.PRIVATE.equals(v1)) return v2; - if(PsiModifier.PUBLIC.equals(v1)) return PsiModifier.PUBLIC; - if(PsiModifier.PRIVATE.equals(v2)) return v1; - - return PsiModifier.PUBLIC; + return compare(v1, v2) < 0 ? v1 : v2; } public static void escalateVisibility(PsiMember modifierListOwner, PsiElement place) throws IncorrectOperationException { diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/generation/OverrideImplementExploreUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/generation/OverrideImplementExploreUtil.java index 6c273b2b8316..f8991e62cbc5 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/generation/OverrideImplementExploreUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/generation/OverrideImplementExploreUtil.java @@ -1,8 +1,10 @@ package com.intellij.codeInsight.generation; import com.intellij.codeInsight.MemberImplementorExplorer; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.NullableLazyValue; +import com.intellij.openapi.util.VolatileNullableLazyValue; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -111,6 +113,17 @@ public class OverrideImplementExploreUtil { } } + public interface MemberImplementorExplorersProvider { + MemberImplementorExplorer[] getExplorers(); + } + + private static final NullableLazyValue<MemberImplementorExplorersProvider> ourExplorersProvider = new VolatileNullableLazyValue<MemberImplementorExplorersProvider>() { + @Override + protected MemberImplementorExplorersProvider compute() { + return ServiceManager.getService(MemberImplementorExplorersProvider.class); + } + }; + public static void collectMethodsToImplement(PsiClass aClass, Map<MethodSignature, PsiMethod> abstracts, Map<MethodSignature, PsiMethod> finals, @@ -132,12 +145,16 @@ public class OverrideImplementExploreUtil { } } - for (final MemberImplementorExplorer implementor : Extensions.getExtensions(MemberImplementorExplorer.EXTENSION_POINT_NAME)) { - for (final PsiMethod method : implementor.getMethodsToImplement(aClass)) { - MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), method.getParameterList(), - method.getTypeParameterList(), PsiSubstitutor.EMPTY, method.isConstructor()); - CandidateInfo info = new CandidateInfo(method, PsiSubstitutor.EMPTY); - result.put(signature, info); + MemberImplementorExplorersProvider explorersProvider = ourExplorersProvider.getValue(); + if (explorersProvider != null) { + for (final MemberImplementorExplorer implementor : explorersProvider.getExplorers()) { + for (final PsiMethod method : implementor.getMethodsToImplement(aClass)) { + MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), method.getParameterList(), + method.getTypeParameterList(), PsiSubstitutor.EMPTY, + method.isConstructor()); + CandidateInfo info = new CandidateInfo(method, PsiSubstitutor.EMPTY); + result.put(signature, info); + } } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index bafbd37eac87..9216b164fb66 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -101,7 +101,7 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple @NotNull private PsiElement getParameterIdentifier() { PsiJavaToken identifier = PsiTreeUtil.getChildOfAnyType(this, PsiIdentifier.class, PsiKeyword.class); - assert identifier != null : this; + assert identifier != null : getClass() + ":" + getText(); return identifier; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index ebc3168758e7..a104ac21c353 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.javadoc; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.SourceTreeToPsiMap; @@ -31,10 +32,8 @@ import com.intellij.psi.scope.processor.FilterScopeProcessor; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.CharTable; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SmartList; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -344,11 +343,12 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo if (hasSignature) { newText.append('('); PsiParameter[] parameters = method.getParameterList().getParameters(); - for (int i = 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - if (i > 0) newText.append(","); - newText.append(parameter.getType().getCanonicalText()); - } + newText.append(StringUtil.join(parameters, new Function<PsiParameter, String>() { + @Override + public String fun(PsiParameter parameter) { + return TypeConversionUtil.erasure(parameter.getType()).getCanonicalText(); + } + }, ",")); newText.append(')'); } newText.append("*/"); diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 50218fe92adf..4e6fa6c6cec0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -616,19 +616,31 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final Map<PsiTypeParameter, PsiType> map1 = classSubstitutor1.getSubstitutionMap(); final Map<PsiTypeParameter, PsiType> map2 = classSubstitutor2.getSubstitutionMap(); if (map1.size() == 1 && map2.size() == 1) { + boolean leftAssignable = InheritanceUtil.isInheritorOrSelf(aClass2, aClass1, true); + boolean rightAssignable = InheritanceUtil.isInheritorOrSelf(aClass1, aClass2, true); final PsiType t1 = map1.values().iterator().next(); final PsiType t2 = map2.values().iterator().next(); boolean raw1 = t1 instanceof PsiClassType && ((PsiClassType)t1).hasParameters(); boolean raw2 = t2 instanceof PsiClassType && ((PsiClassType)t2).hasParameters(); - if (!raw1 && raw2) return Specifics.FIRST; - if (raw1 && !raw2) return Specifics.SECOND; + if (!raw1 && raw2) return leftAssignable ? Specifics.FIRST : Specifics.NEITHER; + if (raw1 && !raw2) return rightAssignable ? Specifics.SECOND : Specifics.NEITHER; final PsiTypeParameter p1 = map1.keySet().iterator().next(); final PsiTypeParameter p2 = map2.keySet().iterator().next(); - final Specifics specifics = checkTypeParams(method1, method2, classSubstitutor1, classSubstitutor2, type1, type2, p1, p2); - if (specifics != null) return specifics; - return chooseHigherDimension(t1, t2); + Specifics specifics = checkTypeParams(method1, method2, classSubstitutor1, classSubstitutor2, type1, type2, p1, p2); + if (specifics == null) { + specifics = chooseHigherDimension(t1, t2); + } + if (specifics != null) { + if (specifics == Specifics.FIRST) { + if (leftAssignable && !rightAssignable) return Specifics.NEITHER; + } + else if (specifics == Specifics.SECOND) { + if (rightAssignable && !leftAssignable) return Specifics.NEITHER; + } + } + return specifics; } return null; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA55510.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA55510.java index ee56cb21ca1a..cda2e457bbe9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA55510.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA55510.java @@ -11,4 +11,12 @@ class BugTestSub extends IdeaBugTest<<error descr="SubMapping is not accessible class BugTestSub1 extends IdeaBugTest<BugTestSub1.SubMapping> { public abstract static class SubMapping extends IdeaBugTest.Mapping {} //fqn here +} + +class AbstractSettings { + interface State {} +} +interface SomeInterface<T> {} +class Settings extends AbstractSettings implements SomeInterface<Settings.MyState> { + static class MyState implements State {} }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67865.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67865.java new file mode 100644 index 000000000000..ab7d8cf9cc2d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67865.java @@ -0,0 +1,11 @@ +import java.util.*; + +abstract class A { + static <T> void foo(List<T> x) { } + static <T extends List<?>> void foo(Collection<T> x) { } + public static void main(String[] args){ + List<List<String>> x = null; + foo<error descr="Ambiguous method call: both 'A.foo(List<List<String>>)' and 'A.foo(Collection<List<String>>)' match">(x)</error>; + foo<error descr="Ambiguous method call: both 'A.foo(List<Object>)' and 'A.foo(Collection<List<?>>)' match">(null)</error>; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterGenerateEnumPrivateConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterGenerateEnumPrivateConstructor.java index 53ec37bf6f57..2c8757516f39 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterGenerateEnumPrivateConstructor.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createConstructorParameterFromField/afterGenerateEnumPrivateConstructor.java @@ -4,7 +4,7 @@ public enum MyEnum VALUE_ONE(myField); private final int myField; - private MyEnum(int myField) { + MyEnum(int myField) { this.myField = myField; } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java new file mode 100644 index 000000000000..9ae8bed1d285 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/afterEnumConstantWithoutClassInitializer.java @@ -0,0 +1,9 @@ +// "Implement Methods" "true" +enum E { + A { + public void foo() { + + } + }; + abstract void foo(); +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java new file mode 100644 index 000000000000..92bbb6aea212 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods/beforeEnumConstantWithoutClassInitializer.java @@ -0,0 +1,5 @@ +// "Implement Methods" "true" +enum E { + <caret>A; + public abstract void foo(); +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateConstructor/afterEnumWithAbstractMethod.java b/java/java-tests/testData/codeInsight/generateConstructor/afterEnumWithAbstractMethod.java index f12bc94ae242..8a38e2b50e73 100644 --- a/java/java-tests/testData/codeInsight/generateConstructor/afterEnumWithAbstractMethod.java +++ b/java/java-tests/testData/codeInsight/generateConstructor/afterEnumWithAbstractMethod.java @@ -7,6 +7,6 @@ public enum Operation { abstract int eval(int x, int y); - private Operation() { + Operation() { } }
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java index f86d79733c73..64bfd011fed6 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java @@ -32,4 +32,10 @@ public class AssertIsNotNull { } Object call() {return new Object();} + + @Contract(<warning descr="A contract clause must be in form arg1, ..., argN -> return-value">"a"</warning>) + void malformedContract() {} + + @Contract(<warning descr="Method takes 2 parameters, while contract clause 0 expects 1">"null -> _"</warning>) + void wrongParameterCount(Object a, boolean b) {} } diff --git a/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink.java b/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink.java new file mode 100644 index 000000000000..f4fb657aeb43 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink.java @@ -0,0 +1,8 @@ +class A { + void method<caret>(boolean a){} + + /** + * {@link #method(boolean)} + */ + void bar() {} +} diff --git a/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink_after.java b/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink_after.java new file mode 100644 index 000000000000..5bcd7ccfd51c --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/JavadocGenericsLink_after.java @@ -0,0 +1,10 @@ +import java.util.List; + +class A { + void method(List<String> y, boolean a){} + + /** + * {@link #method(java.util.List, boolean)} + */ + void bar() {} +} diff --git a/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod.java b/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod.java new file mode 100644 index 000000000000..75730eb16f04 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod.java @@ -0,0 +1,10 @@ +class Test { + protected void fo<caret>o() { + } +} + +class subclass extends Test { + @Override + protected void foo() { + } +} diff --git a/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod_after.java b/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod_after.java new file mode 100644 index 000000000000..b5eabe9cbda5 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/VisibilityOfOverriddenMethod_after.java @@ -0,0 +1,10 @@ +class Test { + void foo() { + } +} + +class subclass extends Test { + @Override + protected void foo() { + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java new file mode 100644 index 000000000000..b5ab59a09c2a --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ImplementMethodsTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight; + +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixAvailabilityTestCase; + +/** + * User: anna + * Date: 10/7/11 + */ +public class ImplementMethodsTest extends LightQuickFixAvailabilityTestCase { + public void test() throws Exception { + doAllTests(); + } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/implementMethods"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index a4686a857c9e..0a31d5eb15f4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -63,14 +63,19 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { } """) type('i') - assertContains("iterable", "if", "int") + def les = myFixture.lookupElementStrings + assert 'iterable' in les + assert 'if' in les + assert 'int' in les type('t') assertContains "iterable" assertEquals 'iterable', lookup.currentItem.lookupString type('er') - assertContains "iterable", "iter" + les = myFixture.lookupElementStrings + assert 'iterable' in les + assert 'iter' in les assertEquals 'iterable', lookup.currentItem.lookupString assert lookup.focused diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index dda5aecf3a81..efc253f27847 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -309,6 +309,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEA57289() { doTest5(false); } public void testIDEA57439() { doTest5(false); } public void testIDEA57312() { doTest5(false); } + public void testIDEA67865() { doTest5(false); } public void testJavaUtilCollections_NoVerify() throws Exception { PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); diff --git a/java/java-tests/testSrc/com/intellij/psi/search/FindUsagesTest.java b/java/java-tests/testSrc/com/intellij/psi/search/FindUsagesTest.java index 7e9bb8425a10..185ec301eadb 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/FindUsagesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/FindUsagesTest.java @@ -24,7 +24,6 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.StdModuleTypes; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.search.searches.MethodReferencesSearch; @@ -57,15 +56,12 @@ public class FindUsagesTest extends PsiTestCase{ public void testOverloadConstructors() throws Exception { PsiClass aClass = myJavaFacade.findClass("B", GlobalSearchScope.allScope(myProject)); - PsiMethod constructor; -// constructor = myJavaFacade.getElementFactory().createConstructor(); -// constructor = aClass.findMethodBySignature(constructor, false); - constructor = aClass.findMethodsByName("B", false)[0]; + PsiMethod constructor = aClass.findMethodsByName("B", false)[0]; PsiMethodCallExpression superCall = (PsiMethodCallExpression) constructor.getBody().getStatements()[0].getFirstChild(); PsiReferenceExpression superExpr = superCall.getMethodExpression(); - String[] fileNames = new String[]{"B.java", "A.java", "A.java", "B.java"}; - int[] starts = new int[]{}; - int[] ends = new int[]{}; + String[] fileNames = {"B.java", "A.java", "A.java", "B.java"}; + int[] starts = {}; + int[] ends = {}; final ArrayList<PsiFile> filesList = new ArrayList<PsiFile>(); final IntArrayList startsList = new IntArrayList(); final IntArrayList endsList = new IntArrayList(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java index 9157e437a526..b7a5662d820e 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java @@ -135,6 +135,13 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { }, false); } + public void testJavadocGenericsLink() throws Exception { + doTest(null, new ParameterInfoImpl[] { + new ParameterInfoImpl(-1, "y", JavaPsiFacade.getElementFactory(getProject()).createTypeFromText("java.util.List<java.lang.String>", null)), + new ParameterInfoImpl(0, "a", PsiType.BOOLEAN) + }, false); + } + public void testParamNameSameAsFieldName() throws Exception { doTest(null, new ParameterInfoImpl[] { new ParameterInfoImpl(0, "fieldName", PsiType.INT) @@ -355,6 +362,10 @@ public class ChangeSignatureTest extends LightRefactoringTestCase { doTest(null, null, "Exception", new SimpleParameterGen(), new SimpleExceptionsGen(), false); } + public void testVisibilityOfOverriddenMethod() throws Exception { + doTest(PsiModifier.PACKAGE_LOCAL, "foo", "void", new ParameterInfoImpl[0], new ThrownExceptionInfo[0], false); + } + public void testRemoveExceptions() throws Exception { doTest(null, null, "void", new SimpleParameterGen(), new SimpleExceptionsGen(), false); } diff --git a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java index d7546e76ac02..0f556dc0bd0c 100644 --- a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java @@ -16,6 +16,7 @@ package com.intellij.psi.search; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -148,10 +149,26 @@ public class LocalSearchScope extends SearchScope { if (scope2 instanceof LocalSearchScope) { return intersectWith((LocalSearchScope)scope2); } + LocalSearchScope nonPhysicalScope = tryIntersectNonPhysicalWith((GlobalSearchScope)scope2); + if (nonPhysicalScope != null) return nonPhysicalScope; return ((GlobalSearchScope)scope2).intersectWith(this); } @Nullable + private LocalSearchScope tryIntersectNonPhysicalWith(@NotNull GlobalSearchScope scope) { + Project project = scope.getProject(); + for (PsiElement element : myScope) { + PsiFile containingFile = element.getContainingFile(); + if (containingFile == null) continue; + if (containingFile.getViewProvider().isPhysical()) return null; + if (project != null && project != containingFile.getProject()) { + return EMPTY; + } + } + return this; + } + + @Nullable private static PsiElement intersectScopeElements(PsiElement element1, PsiElement element2) { if (PsiTreeUtil.isContextAncestor(element1, element2, false)) return element2; if (PsiTreeUtil.isContextAncestor(element2, element1, false)) return element1; diff --git a/platform/core-api/src/com/intellij/psi/tree/IElementType.java b/platform/core-api/src/com/intellij/psi/tree/IElementType.java index b64d76112220..ed349f7ee449 100644 --- a/platform/core-api/src/com/intellij/psi/tree/IElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/IElementType.java @@ -51,7 +51,7 @@ public class IElementType { }; public static final short FIRST_TOKEN_INDEX = 1; - public static final short MAX_INDEXED_TYPES = 15000; + public static final short MAX_INDEXED_TYPES = 20000; private static short ourCounter = FIRST_TOKEN_INDEX; private static IElementType[] ourRegistry = new IElementType[700]; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/SyntheticFileSystemItem.java b/platform/core-impl/src/com/intellij/psi/impl/SyntheticFileSystemItem.java index 782643410849..782643410849 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/SyntheticFileSystemItem.java +++ b/platform/core-impl/src/com/intellij/psi/impl/SyntheticFileSystemItem.java diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ProjectData.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ProjectData.java index 71ef9b0a54a6..385043425595 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ProjectData.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/project/ProjectData.java @@ -23,7 +23,7 @@ public class ProjectData extends AbstractNamedData implements ExternalConfigPath @NotNull String linkedExternalProjectPath) { super(owner, "unnamed"); - myLinkedExternalProjectPath = linkedExternalProjectPath; + myLinkedExternalProjectPath = ExternalSystemApiUtil.toCanonicalPath(linkedExternalProjectPath); myIdeProjectFileDirectoryPath = ExternalSystemApiUtil.toCanonicalPath(ideProjectFileDirectoryPath); } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java index 80795f45afe3..659a32d16728 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemConstants.java @@ -33,6 +33,8 @@ public class ExternalSystemConstants { @NonNls @NotNull public static final String TOOL_WINDOW_PLACE = "ExternalSystem.ToolWindow"; @NonNls @NotNull public static final String TREE_CONTEXT_MENU_PLACE = "ExternalSystem.Tree.Context.Menu"; + @NotNull @NonNls public static final String USE_IN_PROCESS_COMMUNICATION_REGISTRY_KEY = "external.system.in.process"; + @NotNull public static final String DEBUG_RUNNER_ID = "ExternalSystemTaskDebugRunner"; @NotNull public static final String RUNNER_ID = "ExternalSystemTaskRunner"; diff --git a/platform/external-system-impl/external-system-impl.iml b/platform/external-system-impl/external-system-impl.iml index 5767a6c50af9..9f5a52eb7202 100644 --- a/platform/external-system-impl/external-system-impl.iml +++ b/platform/external-system-impl/external-system-impl.iml @@ -4,6 +4,7 @@ <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" /> </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> @@ -16,6 +17,7 @@ <orderEntry type="module" module-name="debugger-impl" /> <orderEntry type="module" module-name="execution-openapi" /> <orderEntry type="module" module-name="vcs-api" /> + <orderEntry type="library" name="Groovy" level="project" /> </component> </module> diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java index d61abed5faa2..98deeacde3b5 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeImpl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java @@ -1,106 +1,66 @@ package com.intellij.openapi.externalSystem.service; import com.intellij.execution.rmi.RemoteServer; -import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager; import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; import com.intellij.openapi.externalSystem.model.task.*; import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver; import com.intellij.openapi.externalSystem.service.remote.*; -import com.intellij.util.Alarm; +import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; import java.util.*; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** * @author Denis Zhdanov * @since 8/8/11 12:51 PM */ -public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> extends RemoteServer +public abstract class AbstractExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> extends RemoteServer implements RemoteExternalSystemFacade<S> { - private static final long DEFAULT_REMOTE_GRADLE_PROCESS_TTL_IN_MS = TimeUnit.MILLISECONDS.convert(3, TimeUnit.MINUTES); - private final ConcurrentMap<Class<?>, RemoteExternalSystemService<S>> myRemotes = ContainerUtil.newConcurrentMap(); private final AtomicReference<S> mySettings = new AtomicReference<S>(); - private final AtomicLong myTtlMs = new AtomicLong(DEFAULT_REMOTE_GRADLE_PROCESS_TTL_IN_MS); - private final Alarm myShutdownAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); - private final AtomicInteger myCallsInProgressNumber = new AtomicInteger(); - private final AtomicReference<ExternalSystemTaskNotificationListener> myNotificationListener = new AtomicReference<ExternalSystemTaskNotificationListener>(new ExternalSystemTaskNotificationListenerAdapter() {}); @NotNull private final RemoteExternalSystemProjectResolverImpl<S> myProjectResolver; @NotNull private final RemoteExternalSystemTaskManagerImpl<S> myTaskManager; - private volatile boolean myStdOutputConfigured; - public ExternalSystemFacadeImpl(@NotNull Class<ExternalSystemProjectResolver<S>> projectResolverClass, - @NotNull Class<ExternalSystemTaskManager<S>> buildManagerClass) + public AbstractExternalSystemFacadeImpl(@NotNull Class<ExternalSystemProjectResolver<S>> projectResolverClass, + @NotNull Class<ExternalSystemTaskManager<S>> buildManagerClass) throws IllegalAccessException, InstantiationException { myProjectResolver = new RemoteExternalSystemProjectResolverImpl<S>(projectResolverClass.newInstance()); myTaskManager = new RemoteExternalSystemTaskManagerImpl<S>(buildManagerClass.newInstance()); - updateAutoShutdownTime(); - } - - @SuppressWarnings("unchecked") - public static void main(String[] args) throws Exception { - if (args.length < 1) { - throw new IllegalArgumentException( - "Can't create external system facade. Reason: given arguments don't contain information about external system resolver to use"); - } - final Class<ExternalSystemProjectResolver<?>> resolverClass = (Class<ExternalSystemProjectResolver<?>>)Class.forName(args[0]); - if (!ExternalSystemProjectResolver.class.isAssignableFrom(resolverClass)) { - throw new IllegalArgumentException(String.format( - "Can't create external system facade. Reason: given external system resolver class (%s) must be IS-A '%s'", - resolverClass, - ExternalSystemProjectResolver.class)); - } - - if (args.length < 2) { - throw new IllegalArgumentException( - "Can't create external system facade. Reason: given arguments don't contain information about external system build manager to use" - ); - } - final Class<ExternalSystemTaskManager<?>> buildManagerClass = (Class<ExternalSystemTaskManager<?>>)Class.forName(args[1]); - if (!ExternalSystemProjectResolver.class.isAssignableFrom(resolverClass)) { - throw new IllegalArgumentException(String.format( - "Can't create external system facade. Reason: given external system build manager (%s) must be IS-A '%s'", - buildManagerClass, ExternalSystemTaskManager.class - )); - } - - ExternalSystemFacadeImpl facade = new ExternalSystemFacadeImpl(resolverClass, buildManagerClass); - facade.init(); - start(facade); } - private void init() throws RemoteException { + protected void init() throws RemoteException { applyProgressManager(RemoteExternalSystemProgressNotificationManager.NULL_OBJECT); } + @Nullable + protected S getSettings() { + return mySettings.get(); + } + + @NotNull + protected ExternalSystemTaskNotificationListener getNotificationListener() { + return myNotificationListener.get(); + } + @SuppressWarnings("unchecked") @NotNull @Override public RemoteExternalSystemProjectResolver<S> getResolver() throws RemoteException, IllegalStateException { try { - return getRemote(RemoteExternalSystemProjectResolver.class, myProjectResolver); + return getService(RemoteExternalSystemProjectResolver.class, myProjectResolver); } catch (Exception e) { throw new IllegalStateException(String.format("Can't create '%s' service", RemoteExternalSystemProjectResolverImpl.class.getName()), @@ -113,67 +73,32 @@ public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> @Override public RemoteExternalSystemTaskManager<S> getTaskManager() throws RemoteException { try { - return getRemote(RemoteExternalSystemTaskManager.class, myTaskManager); + return getService(RemoteExternalSystemTaskManager.class, myTaskManager); } catch (Exception e) { throw new IllegalStateException(String.format("Can't create '%s' service", ExternalSystemTaskManager.class.getName()), e); } } - /** - * Generic method to retrieve exposed implementations of the target interface. - * <p/> - * Uses cached value if it's found; creates new and caches it otherwise. - * - * @param interfaceClass target service interface class - * @param impl service implementation - * @param <I> service interface class - * @param <C> service implementation - * @return implementation of the target service - * @throws IllegalAccessException in case of incorrect assumptions about server class interface - * @throws InstantiationException in case of incorrect assumptions about server class interface - * @throws ClassNotFoundException in case of incorrect assumptions about server class interface - * @throws RemoteException - */ @SuppressWarnings({"unchecked", "IOResourceOpenedButNotSafelyClosed", "UseOfSystemOutOrSystemErr"}) - private <I extends RemoteExternalSystemService<S>, C extends I> I getRemote(@NotNull Class<I> interfaceClass, - @NotNull final C impl) + private <I extends RemoteExternalSystemService<S>, C extends I> I getService(@NotNull Class<I> interfaceClass, + @NotNull final C impl) throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException { Object cachedResult = myRemotes.get(interfaceClass); if (cachedResult != null) { return (I)cachedResult; } - - if (!myStdOutputConfigured) { - myStdOutputConfigured = true; - System.setOut(new LineAwarePrintStream(System.out)); - System.setErr(new LineAwarePrintStream(System.err)); - } - - S settings = mySettings.get(); + S settings = getSettings(); if (settings != null) { - impl.setNotificationListener(myNotificationListener.get()); + impl.setNotificationListener(getNotificationListener()); impl.setSettings(settings); } - impl.setNotificationListener(myNotificationListener.get()); - I proxy = (I)Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { interfaceClass }, new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - myCallsInProgressNumber.incrementAndGet(); - try { - return method.invoke(impl, args); - } - finally { - myCallsInProgressNumber.decrementAndGet(); - updateAutoShutdownTime(); - } - } - }); + impl.setNotificationListener(getNotificationListener()); try { - I stub = (I)UnicastRemoteObject.exportObject(proxy, 0); - I stored = (I)myRemotes.putIfAbsent(interfaceClass, stub); - return stored == null ? stub : stored; + I created = createService(interfaceClass, impl); + I stored = (I)myRemotes.putIfAbsent(interfaceClass, created); + return stored == null ? created : stored; } catch (RemoteException e) { Object raceResult = myRemotes.get(interfaceClass); @@ -190,6 +115,26 @@ public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> } } + /** + * Generic method to retrieve exposed implementations of the target interface. + * <p/> + * Uses cached value if it's found; creates new and caches it otherwise. + * + * @param interfaceClass target service interface class + * @param impl service implementation + * @param <I> service interface class + * @param <C> service implementation + * @return implementation of the target service + * @throws IllegalAccessException in case of incorrect assumptions about server class interface + * @throws InstantiationException in case of incorrect assumptions about server class interface + * @throws ClassNotFoundException in case of incorrect assumptions about server class interface + * @throws RemoteException + */ + @SuppressWarnings({"unchecked", "IOResourceOpenedButNotSafelyClosed", "UseOfSystemOutOrSystemErr"}) + protected abstract <I extends RemoteExternalSystemService<S>, C extends I> I createService(@NotNull Class<I> interfaceClass, + @NotNull final C impl) + throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException; + @Override public boolean isTaskInProgress(@NotNull ExternalSystemTaskId id) throws RemoteException { for (RemoteExternalSystemService service : myRemotes.values()) { @@ -229,10 +174,6 @@ public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> @Override public void applySettings(@NotNull S settings) throws RemoteException { mySettings.set(settings); - long ttl = settings.getRemoteProcessIdleTtlInMs(); - if (ttl > 0) { - myTtlMs.set(ttl); - } List<RemoteExternalSystemService<S>> services = ContainerUtilRt.newArrayList(myRemotes.values()); for (RemoteExternalSystemService<S> service : services) { service.setSettings(settings); @@ -247,26 +188,6 @@ public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> myTaskManager.setNotificationListener(listener); } - /** - * Schedules automatic process termination in {@code #REMOTE_GRADLE_PROCESS_TTL_IN_MS} milliseconds. - * <p/> - * Rationale: it's possible that IJ user performs gradle related activity (e.g. import from gradle) when the works purely - * at IJ. We don't want to keep remote process that communicates with the gradle api then. - */ - private void updateAutoShutdownTime() { - myShutdownAlarm.cancelAllRequests(); - myShutdownAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (myCallsInProgressNumber.get() > 0) { - updateAutoShutdownTime(); - return; - } - System.exit(0); - } - }, (int)myTtlMs.get()); - } - private static class SwallowingNotificationListener implements ExternalSystemTaskNotificationListener { @NotNull private final RemoteExternalSystemProgressNotificationManager myManager; @@ -319,46 +240,4 @@ public class ExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> } } } - - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - private static class LineAwarePrintStream extends PrintStream { - private LineAwarePrintStream(@NotNull final PrintStream delegate) { - super(new OutputStream() { - - @NotNull private final StringBuilder myBuffer = new StringBuilder(); - - @Override - public void write(int b) throws IOException { - char c = (char)b; - myBuffer.append(Character.toString(c)); - if (c == '\n') { - doFlush(); - } - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - int start = off; - int maxOffset = off + len; - for (int i = off; i < maxOffset; i++) { - if (b[i] == '\n') { - myBuffer.append(new String(b, start, i - start + 1)); - doFlush(); - start = i + 1; - } - } - - if (start < maxOffset) { - myBuffer.append(new String(b, start, maxOffset - start)); - } - } - - private void doFlush() { - delegate.print(myBuffer.toString()); - delegate.flush(); - myBuffer.setLength(0); - } - }); - } - } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemCommunicationManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemCommunicationManager.java new file mode 100644 index 000000000000..3b74bcffbde1 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemCommunicationManager.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service; + +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * External system integration consists of common 'external system' functionality and external system-specific code. There are at + * least two approaches how to work with that external system-specific code: + * <pre> + * <ul> + * <li>use it from the ide process;</li> + * <li>create a slave process and perform external system-specific actions there;</li> + * </ul> + * </pre> + * <p/> + * E.g. when we work with particular external system api it might worth to do that at a separate process in order to avoid bad stuff + * like memory leaks to happen at the ide process. However, when external system-specific communication just starts new external + * system-process, there is no point in creating intermediate mediator process just to launch new process. + * <p/> + * That's why that stuff is covered by the current interface, i.e. different implementations are supposed to provide + * different 'in process' modes. + * + * @author Denis Zhdanov + * @since 8/9/13 3:21 PM + */ +public interface ExternalSystemCommunicationManager { + + /** + * Creates new external system facade for the given arguments. + * + * @param id if for which new facade is to be created + * @param externalSystemId target external system id + * @return newly created facade for the given arguments (if it was possible to create one) + * @throws Exception in case something goes wrong + */ + @Nullable + RemoteExternalSystemFacade acquire(@NotNull String id, @NotNull ProjectSystemId externalSystemId) + throws Exception; + + boolean isAlive(@NotNull RemoteExternalSystemFacade facade); + + /** + * Disposes all resources acquired by the current manager. + */ + void clear(); +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeManager.java index 7136ca7fcfa6..5043bd3116e5 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeManager.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemFacadeManager.java @@ -1,53 +1,23 @@ package com.intellij.openapi.externalSystem.service; -import com.intellij.CommonBundle; -import com.intellij.execution.DefaultExecutionResult; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionResult; -import com.intellij.execution.Executor; -import com.intellij.execution.configurations.CommandLineState; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.configurations.RunProfileState; -import com.intellij.execution.configurations.SimpleJavaParameters; -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.process.ProcessTerminatedListener; -import com.intellij.execution.rmi.RemoteProcessSupport; -import com.intellij.execution.runners.ProgramRunner; -import com.intellij.ide.actions.OpenProjectFileChooserDescriptor; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; -import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager; -import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl; import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProgressNotificationManager; import com.intellij.openapi.externalSystem.service.remote.wrapper.ExternalSystemFacadeWrapper; import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsManager; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.IntegrationKey; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.projectRoots.JavaSdkType; -import com.intellij.openapi.projectRoots.JdkUtil; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.SimpleJavaSdkType; -import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.ShutDownTracker; -import com.intellij.psi.PsiBundle; -import com.intellij.util.Alarm; +import com.intellij.openapi.util.registry.Registry; import com.intellij.util.Consumer; -import com.intellij.util.PathUtil; -import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; @@ -57,14 +27,11 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.nio.charset.Charset; import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -79,10 +46,6 @@ import java.util.concurrent.locks.ReentrantLock; */ public class ExternalSystemFacadeManager { - private static final Logger LOG = Logger.getInstance("#" + ExternalSystemFacadeManager.class.getName()); - - private static final String MAIN_CLASS_NAME = ExternalSystemFacadeImpl.class.getName(); - private static final int REMOTE_FAIL_RECOVERY_ATTEMPTS_NUMBER = 3; private final ConcurrentMap<IntegrationKey, RemoteExternalSystemFacade> myFacadeWrappers = ContainerUtil.newConcurrentMap(); @@ -90,43 +53,30 @@ public class ExternalSystemFacadeManager { private final Map<IntegrationKey, Pair<RemoteExternalSystemFacade, ExternalSystemExecutionSettings>> myRemoteFacades = ContainerUtil.newConcurrentMap(); - @NotNull private final Lock myLock = new ReentrantLock(); + @NotNull private final Lock myLock = new ReentrantLock(); + @NotNull private final AtomicBoolean myInProcessCommunication = new AtomicBoolean(); - private final AtomicReference<RemoteExternalSystemProgressNotificationManager> myExportedNotificationManager - = new AtomicReference<RemoteExternalSystemProgressNotificationManager>(); + @NotNull private final AtomicReference<ExternalSystemCommunicationManager> myCommunicationManager = + new AtomicReference<ExternalSystemCommunicationManager>(); - @NotNull private final ExternalSystemProgressNotificationManagerImpl myProgressManager; - @NotNull private final ExternalSystemSettingsManager mySettingsManager; - @NotNull private final RemoteProcessSupport<Object, RemoteExternalSystemFacade, String> mySupport; - @NotNull private final ThreadLocal<ProjectSystemId> myTargetExternalSystemId = new ThreadLocal<ProjectSystemId>(); + @NotNull private final ExternalSystemSettingsManager mySettingsManager; + @NotNull private final RemoteExternalSystemProgressNotificationManager myProgressManager; + @NotNull private final RemoteExternalSystemCommunicationManager myRemoteCommunicationManager; + @NotNull private final InProcessExternalSystemCommunicationManager myInProcessCommunicationManager; public ExternalSystemFacadeManager(@NotNull ExternalSystemSettingsManager settingsManager, - @NotNull ExternalSystemProgressNotificationManager notificationManager) + @NotNull ExternalSystemProgressNotificationManager notificationManager, + @NotNull RemoteExternalSystemCommunicationManager remoteCommunicationManager, + @NotNull InProcessExternalSystemCommunicationManager inProcessCommunicationManager) { mySettingsManager = settingsManager; - myProgressManager = (ExternalSystemProgressNotificationManagerImpl)notificationManager; - mySupport = new RemoteProcessSupport<Object, RemoteExternalSystemFacade, String>(RemoteExternalSystemFacade.class) { - @Override - protected void fireModificationCountChanged() { - } - - @Override - protected String getName(Object o) { - return RemoteExternalSystemFacade.class.getName(); - } - - @Override - protected RunProfileState getRunProfileState(Object o, String configuration, Executor executor) throws ExecutionException { - return createRunProfileState(); - } - }; - - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - public void run() { - shutdown(false); - } - }); + myProgressManager = (RemoteExternalSystemProgressNotificationManager)notificationManager; + myRemoteCommunicationManager = remoteCommunicationManager; + myInProcessCommunicationManager = inProcessCommunicationManager; + boolean inProcessCommunication = Registry.is(ExternalSystemConstants.USE_IN_PROCESS_COMMUNICATION_REGISTRY_KEY, false); + myInProcessCommunication.set(inProcessCommunication); + myCommunicationManager.set(inProcessCommunication ? myInProcessCommunicationManager : myRemoteCommunicationManager); } @NotNull @@ -140,93 +90,6 @@ public class ExternalSystemFacadeManager { return projectManager.getDefaultProject(); } - private RunProfileState createRunProfileState() { - return new CommandLineState(null) { - private SimpleJavaParameters createJavaParameters() throws ExecutionException { - - final SimpleJavaParameters params = new SimpleJavaParameters(); - params.setJdk(new SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome())); - - params.setWorkingDirectory(PathManager.getBinPath()); - final List<String> classPath = ContainerUtilRt.newArrayList(); - - // IDE jars. - classPath.addAll(PathManager.getUtilClassPath()); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ProjectBundle.class), classPath); - ExternalSystemApiUtil.addBundle(params.getClassPath(), "messages.ProjectBundle", ProjectBundle.class); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(PsiBundle.class), classPath); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(Alarm.class), classPath); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(DependencyScope.class), classPath); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ExtensionPointName.class), classPath); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(OpenProjectFileChooserDescriptor.class), classPath); - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ExternalSystemTaskNotificationListener.class), classPath); - - // External system module jars - ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(getClass()), classPath); - ExternalSystemApiUtil.addBundle(params.getClassPath(), "messages.CommonBundle", CommonBundle.class); - params.getClassPath().addAll(classPath); - - params.setMainClass(MAIN_CLASS_NAME); - params.getVMParametersList().addParametersString("-Djava.awt.headless=true"); - - // It may take a while for gradle api to resolve external dependencies. Default RMI timeout - // is 15 seconds (http://download.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html#connectionTimeout), - // we don't want to get EOFException because of that. - params.getVMParametersList().addParametersString( - "-Dsun.rmi.transport.connectionTimeout=" + String.valueOf(TimeUnit.HOURS.toMillis(1)) - ); -// params.getVMParametersList().addParametersString("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5009"); - - ProjectSystemId externalSystemId = myTargetExternalSystemId.get(); - if (externalSystemId != null) { - ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId); - if (manager != null) { - params.getClassPath().add(PathUtil.getJarPathForClass(manager.getProjectResolverClass().getClass())); - params.getProgramParametersList().add(manager.getProjectResolverClass().getName()); - params.getProgramParametersList().add(manager.getTaskManagerClass().getName()); - manager.enhanceParameters(params); - } - } - - return params; - } - - @Override - @NotNull - public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { - ProcessHandler processHandler = startProcess(); - return new DefaultExecutionResult(null, processHandler, AnAction.EMPTY_ARRAY); - } - - @NotNull - protected OSProcessHandler startProcess() throws ExecutionException { - SimpleJavaParameters params = createJavaParameters(); - Sdk sdk = params.getJdk(); - if (sdk == null) { - throw new ExecutionException("No sdk is defined. Params: " + params); - } - - final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine( - ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), - params, - false - ); - final OSProcessHandler processHandler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) { - @Override - public Charset getCharset() { - return commandLine.getCharset(); - } - }; - ProcessTerminatedListener.attach(processHandler); - return processHandler; - } - }; - } - - public synchronized void shutdown(boolean wait) { - mySupport.stopAll(wait); - } - public void onProjectRename(@NotNull String oldName, @NotNull String newName) { onProjectRename(myFacadeWrappers, oldName, newName); onProjectRename(myRemoteFacades, oldName, newName); @@ -254,9 +117,9 @@ public class ExternalSystemFacadeManager { } } } - + /** - * @return gradle api facade to use + * @return gradle api facade to use * @throws Exception in case of inability to return the facade */ @NotNull @@ -271,7 +134,8 @@ public class ExternalSystemFacadeManager { final RemoteExternalSystemFacade facade = myFacadeWrappers.get(key); if (facade == null) { final RemoteExternalSystemFacade newFacade = (RemoteExternalSystemFacade)Proxy.newProxyInstance( - ExternalSystemFacadeManager.class.getClassLoader(), new Class[]{RemoteExternalSystemFacade.class, Consumer.class}, new MyHandler(key) + ExternalSystemFacadeManager.class.getClassLoader(), new Class[]{RemoteExternalSystemFacade.class, Consumer.class}, + new MyHandler(key) ); myFacadeWrappers.putIfAbsent(key, newFacade); } @@ -299,6 +163,12 @@ public class ExternalSystemFacadeManager { @SuppressWarnings("ConstantConditions") @NotNull private RemoteExternalSystemFacade doGetFacade(@NotNull IntegrationKey key, @NotNull Project project) throws Exception { + boolean currentInProcess = Registry.is(ExternalSystemConstants.USE_IN_PROCESS_COMMUNICATION_REGISTRY_KEY, false); + if (myInProcessCommunication.getAndSet(currentInProcess) != currentInProcess) { + myCommunicationManager.get().clear(); + myCommunicationManager.set(currentInProcess ? myInProcessCommunicationManager : myRemoteCommunicationManager); + } + ExternalSystemManager manager = ExternalSystemApiUtil.getManager(key.getExternalSystemId()); if (project.isDisposed() || manager == null) { return RemoteExternalSystemFacade.NULL_OBJECT; @@ -315,7 +185,7 @@ public class ExternalSystemFacadeManager { return pair.first; } if (pair != null) { - mySupport.stopAll(true); + myCommunicationManager.get().clear(); myFacadeWrappers.clear(); myRemoteFacades.clear(); } @@ -329,16 +199,14 @@ public class ExternalSystemFacadeManager { @SuppressWarnings("unchecked") @NotNull private RemoteExternalSystemFacade doCreateFacade(@NotNull IntegrationKey key, @NotNull Project project) throws Exception { - myTargetExternalSystemId.set(key.getExternalSystemId()); - final RemoteExternalSystemFacade facade = mySupport.acquire(this, project.getName()); - myTargetExternalSystemId.set(null); + final RemoteExternalSystemFacade facade = myCommunicationManager.get().acquire(project.getName(), key.getExternalSystemId()); if (facade == null) { - throw new IllegalStateException("Can't obtain facade to working with gradle api at the remote process. Project: " + project); + throw new IllegalStateException("Can't obtain facade to working with external api at the remote process. Project: " + project); } Disposer.register(project, new Disposable() { @Override public void dispose() { - mySupport.stopAll(true); + myCommunicationManager.get().clear(); myFacadeWrappers.clear(); myRemoteFacades.clear(); } @@ -349,22 +217,6 @@ public class ExternalSystemFacadeManager { Pair<RemoteExternalSystemFacade, ExternalSystemExecutionSettings> newPair = Pair.create(result, settings); myRemoteFacades.put(key, newPair); result.applySettings(newPair.second); - RemoteExternalSystemProgressNotificationManager exported = myExportedNotificationManager.get(); - if (exported == null) { - try { - exported = (RemoteExternalSystemProgressNotificationManager)UnicastRemoteObject.exportObject(myProgressManager, 0); - myExportedNotificationManager.set(exported); - } - catch (RemoteException e) { - exported = myExportedNotificationManager.get(); - } - } - if (exported == null) { - LOG.warn("Can't export progress manager"); - } - else { - result.applyProgressManager(exported); - } return result; } @@ -373,10 +225,10 @@ public class ExternalSystemFacadeManager { @NotNull IntegrationKey key, @NotNull Pair<RemoteExternalSystemFacade, ExternalSystemExecutionSettings> pair) { - // Check if remote process is alive. + if (!myCommunicationManager.get().isAlive(pair.first)) { + return false; + } try { - pair.first.getResolver(); - ExternalSystemExecutionSettings currentSettings = mySettingsManager.getExecutionSettings(project, key.getExternalProjectConfigPath(), key.getExternalSystemId()); if (!currentSettings.equals(pair.second)) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java index cc2225bf4f21..2edb0f53dd9d 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ExternalSystemStartupActivity.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.externalSystem.service; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.ProjectRenameAware; @@ -36,6 +37,9 @@ public class ExternalSystemStartupActivity implements StartupActivity { @Override public void runActivity(@NotNull final Project project) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return; + } Runnable task = new Runnable() { @SuppressWarnings("unchecked") @Override diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemCommunicationManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemCommunicationManager.java new file mode 100644 index 000000000000..87405e077bbc --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemCommunicationManager.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service; + +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.service.remote.wrapper.ExternalSystemFacadeWrapper; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Denis Zhdanov + * @since 8/9/13 4:00 PM + */ +public class InProcessExternalSystemCommunicationManager implements ExternalSystemCommunicationManager { + + @SuppressWarnings("unchecked") + @Nullable + @Override + public RemoteExternalSystemFacade acquire(@NotNull String id, @NotNull ProjectSystemId externalSystemId) throws Exception { + ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId); + assert manager != null; + return new InProcessExternalSystemFacadeImpl(manager.getProjectResolverClass(), manager.getTaskManagerClass()); + } + + @Override + public boolean isAlive(@NotNull RemoteExternalSystemFacade facade) { + RemoteExternalSystemFacade toCheck = facade; + if (facade instanceof ExternalSystemFacadeWrapper) { + toCheck = ((ExternalSystemFacadeWrapper)facade).getDelegate(); + + } + return toCheck instanceof InProcessExternalSystemFacadeImpl; + } + + @Override + public void clear() { + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemFacadeImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemFacadeImpl.java new file mode 100644 index 000000000000..a0b0141f8a1c --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/InProcessExternalSystemFacadeImpl.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service; + +import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; +import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver; +import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager; +import org.jetbrains.annotations.NotNull; + +import java.rmi.RemoteException; + +/** + * @author Denis Zhdanov + * @since 8/9/13 5:42 PM + */ +public class InProcessExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> extends AbstractExternalSystemFacadeImpl<S> { + + public InProcessExternalSystemFacadeImpl(@NotNull Class<ExternalSystemProjectResolver<S>> projectResolverClass, + @NotNull Class<ExternalSystemTaskManager<S>> buildManagerClass) + throws IllegalAccessException, InstantiationException + { + super(projectResolverClass, buildManagerClass); + } + + @Override + protected <I extends RemoteExternalSystemService<S>, C extends I> I createService(@NotNull Class<I> interfaceClass, @NotNull C impl) + throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException + { + return impl; + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemCommunicationManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemCommunicationManager.java new file mode 100644 index 000000000000..894831feb78d --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemCommunicationManager.java @@ -0,0 +1,257 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service; + +import com.intellij.CommonBundle; +import com.intellij.execution.DefaultExecutionResult; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.ExecutionResult; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.CommandLineState; +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.configurations.SimpleJavaParameters; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.process.ProcessTerminatedListener; +import com.intellij.execution.rmi.RemoteProcessSupport; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.ide.actions.OpenProjectFileChooserDescriptor; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.externalSystem.ExternalSystemManager; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager; +import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl; +import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProgressNotificationManager; +import com.intellij.openapi.externalSystem.service.remote.wrapper.ExternalSystemFacadeWrapper; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.project.ProjectBundle; +import com.intellij.openapi.projectRoots.JavaSdkType; +import com.intellij.openapi.projectRoots.JdkUtil; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SimpleJavaSdkType; +import com.intellij.openapi.roots.DependencyScope; +import com.intellij.openapi.util.ShutDownTracker; +import com.intellij.psi.PsiBundle; +import com.intellij.util.Alarm; +import com.intellij.util.PathUtil; +import com.intellij.util.SystemProperties; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.charset.Charset; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Denis Zhdanov + * @since 8/9/13 3:37 PM + */ +public class RemoteExternalSystemCommunicationManager implements ExternalSystemCommunicationManager { + + private static final Logger LOG = Logger.getInstance("#" + RemoteExternalSystemCommunicationManager.class.getName()); + + private static final String MAIN_CLASS_NAME = RemoteExternalSystemFacadeImpl.class.getName(); + + private final AtomicReference<RemoteExternalSystemProgressNotificationManager> myExportedNotificationManager + = new AtomicReference<RemoteExternalSystemProgressNotificationManager>(); + + @NotNull private final ThreadLocal<ProjectSystemId> myTargetExternalSystemId = new ThreadLocal<ProjectSystemId>(); + + @NotNull private final ExternalSystemProgressNotificationManagerImpl myProgressManager; + @NotNull private final RemoteProcessSupport<Object, RemoteExternalSystemFacade, String> mySupport; + + public RemoteExternalSystemCommunicationManager(@NotNull ExternalSystemProgressNotificationManager notificationManager) { + myProgressManager = (ExternalSystemProgressNotificationManagerImpl)notificationManager; + mySupport = new RemoteProcessSupport<Object, RemoteExternalSystemFacade, String>(RemoteExternalSystemFacade.class) { + @Override + protected void fireModificationCountChanged() { + } + + @Override + protected String getName(Object o) { + return RemoteExternalSystemFacade.class.getName(); + } + + @Override + protected RunProfileState getRunProfileState(Object o, String configuration, Executor executor) throws ExecutionException { + return createRunProfileState(); + } + }; + + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + public void run() { + shutdown(false); + } + }); + } + + public synchronized void shutdown(boolean wait) { + mySupport.stopAll(wait); + } + + private RunProfileState createRunProfileState() { + return new CommandLineState(null) { + private SimpleJavaParameters createJavaParameters() throws ExecutionException { + + final SimpleJavaParameters params = new SimpleJavaParameters(); + params.setJdk(new SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome())); + + params.setWorkingDirectory(PathManager.getBinPath()); + final List<String> classPath = ContainerUtilRt.newArrayList(); + + // IDE jars. + classPath.addAll(PathManager.getUtilClassPath()); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ProjectBundle.class), classPath); + ExternalSystemApiUtil.addBundle(params.getClassPath(), "messages.ProjectBundle", ProjectBundle.class); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(PsiBundle.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(Alarm.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(DependencyScope.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ExtensionPointName.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(OpenProjectFileChooserDescriptor.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(ExternalSystemTaskNotificationListener.class), classPath); + + // External system module jars + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(getClass()), classPath); + ExternalSystemApiUtil.addBundle(params.getClassPath(), "messages.CommonBundle", CommonBundle.class); + params.getClassPath().addAll(classPath); + + params.setMainClass(MAIN_CLASS_NAME); + params.getVMParametersList().addParametersString("-Djava.awt.headless=true"); + + // It may take a while for gradle api to resolve external dependencies. Default RMI timeout + // is 15 seconds (http://download.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html#connectionTimeout), + // we don't want to get EOFException because of that. + params.getVMParametersList().addParametersString( + "-Dsun.rmi.transport.connectionTimeout=" + String.valueOf(TimeUnit.HOURS.toMillis(1)) + ); +// params.getVMParametersList().addParametersString("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5009"); + + ProjectSystemId externalSystemId = myTargetExternalSystemId.get(); + if (externalSystemId != null) { + ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId); + if (manager != null) { + params.getClassPath().add(PathUtil.getJarPathForClass(manager.getProjectResolverClass().getClass())); + params.getProgramParametersList().add(manager.getProjectResolverClass().getName()); + params.getProgramParametersList().add(manager.getTaskManagerClass().getName()); + manager.enhanceParameters(params); + } + } + + return params; + } + + @Override + @NotNull + public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + ProcessHandler processHandler = startProcess(); + return new DefaultExecutionResult(null, processHandler, AnAction.EMPTY_ARRAY); + } + + @NotNull + protected OSProcessHandler startProcess() throws ExecutionException { + SimpleJavaParameters params = createJavaParameters(); + Sdk sdk = params.getJdk(); + if (sdk == null) { + throw new ExecutionException("No sdk is defined. Params: " + params); + } + + final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine( + ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), + params, + false + ); + final OSProcessHandler processHandler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) { + @Override + public Charset getCharset() { + return commandLine.getCharset(); + } + }; + ProcessTerminatedListener.attach(processHandler); + return processHandler; + } + }; + } + + @Nullable + @Override + public RemoteExternalSystemFacade acquire(@NotNull String id, @NotNull ProjectSystemId externalSystemId) + throws Exception + { + myTargetExternalSystemId.set(externalSystemId); + final RemoteExternalSystemFacade facade; + try { + facade = mySupport.acquire(this, id); + } + finally { + myTargetExternalSystemId.set(null); + } + if (facade == null) { + return null; + } + + RemoteExternalSystemProgressNotificationManager exported = myExportedNotificationManager.get(); + if (exported == null) { + try { + exported = (RemoteExternalSystemProgressNotificationManager)UnicastRemoteObject.exportObject(myProgressManager, 0); + myExportedNotificationManager.set(exported); + } + catch (RemoteException e) { + exported = myExportedNotificationManager.get(); + } + } + if (exported == null) { + LOG.warn("Can't export progress manager"); + } + else { + facade.applyProgressManager(exported); + } + return facade; + } + + @Override + public boolean isAlive(@NotNull RemoteExternalSystemFacade facade) { + RemoteExternalSystemFacade toCheck = facade; + if (facade instanceof ExternalSystemFacadeWrapper) { + toCheck = ((ExternalSystemFacadeWrapper)facade).getDelegate(); + + } + if (toCheck instanceof InProcessExternalSystemFacadeImpl) { + return false; + } + try { + facade.getResolver(); + return true; + } + catch (RemoteException e) { + return false; + } + } + + @Override + public void clear() { + mySupport.stopAll(true); + } +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java new file mode 100644 index 000000000000..16d181ea7bc3 --- /dev/null +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java @@ -0,0 +1,188 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service; + +import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; +import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver; +import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager; +import com.intellij.util.Alarm; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author Denis Zhdanov + * @since 8/9/13 4:28 PM + */ +public class RemoteExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> extends AbstractExternalSystemFacadeImpl<S> { + + private static final long DEFAULT_REMOTE_PROCESS_TTL_IN_MS = TimeUnit.MILLISECONDS.convert(3, TimeUnit.MINUTES); + + private final AtomicInteger myCallsInProgressNumber = new AtomicInteger(); + private final Alarm myShutdownAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); + private final AtomicLong myTtlMs = new AtomicLong(DEFAULT_REMOTE_PROCESS_TTL_IN_MS); + + private volatile boolean myStdOutputConfigured; + + public RemoteExternalSystemFacadeImpl(@NotNull Class<ExternalSystemProjectResolver<S>> projectResolverClass, + @NotNull Class<ExternalSystemTaskManager<S>> buildManagerClass) + throws IllegalAccessException, InstantiationException + { + super(projectResolverClass, buildManagerClass); + updateAutoShutdownTime(); + } + + @SuppressWarnings("unchecked") + public static void main(String[] args) throws Exception { + if (args.length < 1) { + throw new IllegalArgumentException( + "Can't create external system facade. Reason: given arguments don't contain information about external system resolver to use"); + } + final Class<ExternalSystemProjectResolver<?>> resolverClass = (Class<ExternalSystemProjectResolver<?>>)Class.forName(args[0]); + if (!ExternalSystemProjectResolver.class.isAssignableFrom(resolverClass)) { + throw new IllegalArgumentException(String.format( + "Can't create external system facade. Reason: given external system resolver class (%s) must be IS-A '%s'", + resolverClass, + ExternalSystemProjectResolver.class)); + } + + if (args.length < 2) { + throw new IllegalArgumentException( + "Can't create external system facade. Reason: given arguments don't contain information about external system build manager to use" + ); + } + final Class<ExternalSystemTaskManager<?>> buildManagerClass = (Class<ExternalSystemTaskManager<?>>)Class.forName(args[1]); + if (!ExternalSystemProjectResolver.class.isAssignableFrom(resolverClass)) { + throw new IllegalArgumentException(String.format( + "Can't create external system facade. Reason: given external system build manager (%s) must be IS-A '%s'", + buildManagerClass, ExternalSystemTaskManager.class + )); + } + + RemoteExternalSystemFacadeImpl facade = new RemoteExternalSystemFacadeImpl(resolverClass, buildManagerClass); + facade.init(); + start(facade); + } + + @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed", "unchecked", "UseOfSystemOutOrSystemErr"}) + @Override + protected <I extends RemoteExternalSystemService<S>, C extends I> I createService(@NotNull Class<I> interfaceClass, @NotNull final C impl) + throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException + { + if (!myStdOutputConfigured) { + myStdOutputConfigured = true; + System.setOut(new LineAwarePrintStream(System.out)); + System.setErr(new LineAwarePrintStream(System.err)); + } + + I proxy = (I)Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + myCallsInProgressNumber.incrementAndGet(); + try { + return method.invoke(impl, args); + } + finally { + myCallsInProgressNumber.decrementAndGet(); + updateAutoShutdownTime(); + } + } + }); + return (I)UnicastRemoteObject.exportObject(proxy, 0); + } + + @Override + public void applySettings(@NotNull S settings) throws RemoteException { + super.applySettings(settings); + long ttl = settings.getRemoteProcessIdleTtlInMs(); + if (ttl > 0) { + myTtlMs.set(ttl); + } + } + + /** + * Schedules automatic process termination in {@code #REMOTE_GRADLE_PROCESS_TTL_IN_MS} milliseconds. + * <p/> + * Rationale: it's possible that IJ user performs gradle related activity (e.g. import from gradle) when the works purely + * at IJ. We don't want to keep remote process that communicates with the gradle api then. + */ + private void updateAutoShutdownTime() { + myShutdownAlarm.cancelAllRequests(); + myShutdownAlarm.addRequest(new Runnable() { + @Override + public void run() { + if (myCallsInProgressNumber.get() > 0) { + updateAutoShutdownTime(); + return; + } + System.exit(0); + } + }, (int)myTtlMs.get()); + } + + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + private static class LineAwarePrintStream extends PrintStream { + private LineAwarePrintStream(@NotNull final PrintStream delegate) { + super(new OutputStream() { + + @NotNull private final StringBuilder myBuffer = new StringBuilder(); + + @Override + public void write(int b) throws IOException { + char c = (char)b; + myBuffer.append(Character.toString(c)); + if (c == '\n') { + doFlush(); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + int start = off; + int maxOffset = off + len; + for (int i = off; i < maxOffset; i++) { + if (b[i] == '\n') { + myBuffer.append(new String(b, start, i - start + 1)); + doFlush(); + start = i + 1; + } + } + + if (start < maxOffset) { + myBuffer.append(new String(b, start, maxOffset - start)); + } + } + + private void doFlush() { + delegate.print(myBuffer.toString()); + delegate.flush(); + myBuffer.setLength(0); + } + }); + } + } + +} diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java index e5be5273838e..b24cb1cdd1be 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java @@ -141,10 +141,7 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable(); LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); try { - if (!hasUnresolved) { // There is a possible case that a project has been successfully imported from external model and after - // that network/repo goes down. We don't want to drop existing binary mappings then. - removeObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel); - } + filterUpToDateAndRemoveObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel, hasUnresolved); // Import missing library dependencies. if (!toImport.isEmpty()) { @@ -166,9 +163,6 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< { for (LibraryDependencyData dependencyData : toImport) { LibraryData libraryData = dependencyData.getTarget(); - if (libraryData.isUnresolved()) { - continue; - } switch (dependencyData.getLevel()) { case MODULE: @SuppressWarnings("ConstantConditions") Library moduleLib = moduleLibraryTable.createLibrary(dependencyData.getName()); @@ -199,10 +193,11 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< } } - private static void removeObsolete(@NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport, - @NotNull Map<String, LibraryDependencyData> projectLibrariesToImport, - @NotNull Set<LibraryDependencyData> toImport, - @NotNull ModifiableRootModel moduleRootModel) + private static void filterUpToDateAndRemoveObsolete(@NotNull Map<Set<String>, LibraryDependencyData> moduleLibrariesToImport, + @NotNull Map<String, LibraryDependencyData> projectLibrariesToImport, + @NotNull Set<LibraryDependencyData> toImport, + @NotNull ModifiableRootModel moduleRootModel, + boolean hasUnresolvedLibraries) { Set<String> moduleLibraryKey = ContainerUtilRt.newHashSet(); for (OrderEntry entry : moduleRootModel.getOrderEntries()) { @@ -227,12 +222,14 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< else if (entry instanceof LibraryOrderEntry) { String libraryName = ((LibraryOrderEntry)entry).getLibraryName(); LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName); - if (existing == null) { - moduleRootModel.removeOrderEntry(entry); - } - else { + if (existing != null) { toImport.remove(existing); } + else if (!hasUnresolvedLibraries) { + // There is a possible case that a project has been successfully imported from external model and after + // that network/repo goes down. We don't want to drop existing binary mappings then. + moduleRootModel.removeOrderEntry(entry); + } } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java index 3aed54aa7c25..81ddcdca9405 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java @@ -36,6 +36,11 @@ public class ExternalSystemFacadeWrapper<S extends ExternalSystemExecutionSettin } @NotNull + public RemoteExternalSystemFacade<S> getDelegate() { + return myDelegate; + } + + @NotNull @Override public RemoteExternalSystemProjectResolver<S> getResolver() throws RemoteException, IllegalStateException { return new ExternalSystemProjectResolverWrapper<S>(myDelegate.getResolver(), myProgressManager); diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/ExternalProjectServiceTest.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/ExternalProjectServiceTest.groovy new file mode 100644 index 000000000000..88cc0de53506 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/service/project/ExternalProjectServiceTest.groovy @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.service.project + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.project.ProjectData +import com.intellij.openapi.externalSystem.test.AbstractExternalSystemTest +import com.intellij.openapi.externalSystem.test.ExternalProjectBuilder +import com.intellij.openapi.externalSystem.test.ExternalSystemTestUtil +import com.intellij.openapi.roots.LibraryOrderEntry +import com.intellij.openapi.roots.OrderEntry; + +/** + * @author Denis Zhdanov + * @since 8/8/13 5:17 PM + */ +public class ExternalProjectServiceTest extends AbstractExternalSystemTest { + + void 'test no duplicate library dependency is added on subsequent refresh when there is an unresolved library'() { + DataNode<ProjectData> projectNode = new ExternalProjectBuilder(projectDir: projectDir). + project { + module('module') { + lib('lib1') + lib('lib2', unresolved: true) } } + + applyProjectState([projectNode, projectNode]) + + def helper = ServiceManager.getService(ProjectStructureHelper.class) + def module = helper.findIdeModule('module', project) + assertNotNull(module) + + def facade = ServiceManager.getService(PlatformFacade.class) + def entries = facade.getOrderEntries(module) + def dependencies = [:].withDefault { 0 } + for (OrderEntry entry : entries) { + if (entry instanceof LibraryOrderEntry) { + def name = (entry as LibraryOrderEntry).libraryName + dependencies[name]++ + } + } + ExternalSystemTestUtil.assertMapsEqual(['lib1': 1, 'lib2': 1], dependencies) + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy new file mode 100644 index 000000000000..d501ac8211e7 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.externalSystem.ExternalSystemManager +import com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.project.ProjectData +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ex.ProjectRootManagerEx +import com.intellij.openapi.util.io.FileUtil +import com.intellij.testFramework.SkipInHeadlessEnvironment +import com.intellij.testFramework.UsefulTestCase +import com.intellij.testFramework.fixtures.IdeaProjectTestFixture +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable + +import java.lang.reflect.Field +import java.lang.reflect.Modifier + +/** + * @author Denis Zhdanov + * @since 8/7/13 2:04 PM + */ +@SkipInHeadlessEnvironment +abstract class AbstractExternalSystemTest extends UsefulTestCase { + + static File tmpDir + + IdeaProjectTestFixture testFixture + Project project + File projectDir + + @Override + protected void setUp() throws Exception { + super.setUp() + + ensureTempDirCreated() + + testFixture = IdeaTestFixtureFactory.fixtureFactory.createFixtureBuilder(name).fixture + testFixture.setUp() + project = testFixture.project + + projectDir = new File(tmpDir, getTestName(false)); + projectDir.mkdirs(); + + def externalSystemManager = new TestExternalSystemManager(project) + def area = Extensions.getArea(null) + def externalSystemManagerEP = area.getExtensionPoint(ExternalSystemManager.EP_NAME) + externalSystemManagerEP.registerExtension(externalSystemManager) + } + + private static void ensureTempDirCreated() { + if (tmpDir != null) { + return + } + + tmpDir = new File(FileUtil.tempDirectory, "externalSystemTests") + FileUtil.delete(tmpDir) + tmpDir.mkdirs() + } + + @Override + protected void tearDown() throws Exception { + project = null + UIUtil.invokeAndWaitIfNeeded { + try { + testFixture.tearDown(); + testFixture = null; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + if (!FileUtil.delete(projectDir) && projectDir.exists()) { + System.err.println("Cannot delete " + projectDir); + //printDirectoryContent(myDir); + projectDir.deleteOnExit(); + } + + super.tearDown(); + resetClassFields(getClass()); + } + + private void resetClassFields(@Nullable Class<?> aClass) { + if (aClass == null) { + return + } + + for (Field field : aClass.declaredFields) { + final int modifiers = field.modifiers; + if ((modifiers & Modifier.FINAL) == 0 && (modifiers & Modifier.STATIC) == 0 && !field.getType().isPrimitive()) { + field.setAccessible(true); + try { + field.set(this, null); + } + catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + if (aClass != AbstractExternalSystemTest.class) { + resetClassFields(aClass.getSuperclass()); + } + } + + protected void applyProjectState(@NotNull List<DataNode<ProjectData>> states) { + def dataManager = ServiceManager.getService(ProjectDataManager.class) + for (DataNode<ProjectData> node : states) { + ExternalSystemApiUtil.executeProjectChangeAction(true, { + ProjectRootManagerEx.getInstanceEx(project).mergeRootsChangesDuring { + dataManager.importData(node.key, [node], project, true) + } }) + } + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalProjectBuilder.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalProjectBuilder.groovy new file mode 100644 index 000000000000..45b6260aee79 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalProjectBuilder.groovy @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.ProjectKeys +import com.intellij.openapi.externalSystem.model.project.* +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.module.ModuleTypeId +import com.intellij.openapi.roots.DependencyScope +import com.intellij.util.BooleanFunction +import org.jetbrains.annotations.NotNull + +import static com.intellij.openapi.externalSystem.test.ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID +/** + * @author Denis Zhdanov + * @since 8/8/13 12:42 PM + */ +class ExternalProjectBuilder extends BuilderSupport { + + File projectDir + DataNode<ProjectData> projectNode; + + @Override + protected void setParent(Object parent, Object child) { + } + + @Override + protected Object createNode(Object name) { + createNode(name, [:]) + } + + @Override + protected Object createNode(Object name, Object value) { + createNode(name, [name: value]) + } + + @Override + protected Object createNode(Object name, Map attributes, Object value) { + createNode(name, [name: value] + attributes) + } + + @Override + protected Object createNode(Object name, Map attributes) { + switch (name) { + case 'project': + ProjectData projectData = new ProjectData(TEST_EXTERNAL_SYSTEM_ID, projectDir.path, projectDir.path) + projectNode = new DataNode<ProjectData>(ProjectKeys.PROJECT, projectData, null) + return projectNode + case 'module': + String moduleFilePath = attributes.moduleFilePath ?: projectDir.path + String externalConfigPath = attributes.externalConfigPath ?: projectDir.path + ModuleData moduleData = new ModuleData(TEST_EXTERNAL_SYSTEM_ID, + ModuleTypeId.JAVA_MODULE, + attributes.name, + moduleFilePath, + externalConfigPath) + return (current as DataNode).createChild(ProjectKeys.MODULE, moduleData) + case 'lib': + DataNode<ModuleData> parentNode = current as DataNode + LibraryDependencyData data = new LibraryDependencyData(parentNode.data, + getLibrary(attributes.name, attributes), + getLevel(attributes)) + data.scope = getScope(attributes) + return parentNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, data) + + default: throw new IllegalArgumentException("Unexpected entry: $name"); + } + } + + @NotNull + private LibraryData getLibrary(@NotNull String name, @NotNull Map attributes) { + DataNode<LibraryData> existing = ExternalSystemApiUtil.find(projectNode, ProjectKeys.LIBRARY, { + DataNode<LibraryData> node -> node.data.name == name + } as BooleanFunction) + if (existing != null) { + return existing.data + } + LibraryData result = new LibraryData(TEST_EXTERNAL_SYSTEM_ID, name, attributes.unresolved as boolean) + ['bin': LibraryPathType.BINARY, 'src': LibraryPathType.SOURCE, 'doc': LibraryPathType.DOC].each { + key, type -> attributes[key]?.each { result.addPath(type, it as String) } + } + projectNode.createChild(ProjectKeys.LIBRARY, result) + result + } + + @NotNull + private static LibraryLevel getLevel(@NotNull Map attributes) { + try { + return LibraryLevel.valueOf(attributes.level.toUpperCase()) + } + catch (Exception ignored) { + return LibraryLevel.PROJECT + } + } + + @NotNull + private static DependencyScope getScope(@NotNull Map attributes) { + try { + return DependencyScope.valueOf(attributes.scope.toUpperCase()) + } + catch (Exception ignored) { + return DependencyScope.COMPILE + } + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestUtil.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestUtil.java new file mode 100644 index 000000000000..bf4c2b306e4c --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemTestUtil.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test; + +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.util.containers.ContainerUtilRt; +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; + +import java.util.Map; + +/** + * @author Denis Zhdanov + * @since 8/8/13 12:50 PM + */ +public class ExternalSystemTestUtil { + + public static final ProjectSystemId TEST_EXTERNAL_SYSTEM_ID = new ProjectSystemId("TEST_EXTERNAL_SYSTEM_ID"); + + public static final Topic<TestExternalSystemSettingsListener> SETTINGS_TOPIC = Topic.create( + "TEST_EXTERNAL_SYSTEM_SETTINGS", TestExternalSystemSettingsListener.class + ); + + private ExternalSystemTestUtil() { + } + + public static void assertMapsEqual(@NotNull Map<?, ?> expected, @NotNull Map<?, ?> actual) { + Map<?, ?> local = ContainerUtilRt.newHashMap(expected); + for (Map.Entry<?, ?> entry : actual.entrySet()) { + Object expectedValue = local.remove(entry.getKey()); + if (expectedValue == null) { + Assert.fail(String.format("Expected to find '%s' -> '%s' mapping but it doesn't exist", entry.getKey(), entry.getValue())); + } + if (!expectedValue.equals(entry.getValue())) { + Assert.fail( + String.format("Expected to find '%s' value for the key '%s' but got '%s'", expectedValue, entry.getKey(), entry.getValue()) + ); + } + } + if (!local.isEmpty()) { + Assert.fail("No mappings found for the following keys: " + local.keySet()); + } + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalProjectSettings.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalProjectSettings.java new file mode 100644 index 000000000000..17d927013c41 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalProjectSettings.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test; + +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 8/8/13 5:12 PM + */ +public class TestExternalProjectSettings extends ExternalProjectSettings { + + @NotNull + @Override + public ExternalProjectSettings clone() { + throw new UnsupportedOperationException(); + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemExecutionSettings.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemExecutionSettings.groovy new file mode 100644 index 000000000000..3acf60733d8c --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemExecutionSettings.groovy @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings + +/** + * @author Denis Zhdanov + * @since 8/8/13 5:22 PM + */ +class TestExternalSystemExecutionSettings extends ExternalSystemExecutionSettings { +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemLocalSettings.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemLocalSettings.groovy new file mode 100644 index 000000000000..94051b2614d9 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemLocalSettings.groovy @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings +import com.intellij.openapi.project.Project +import org.jetbrains.annotations.NotNull +/** + * @author Denis Zhdanov + * @since 8/8/13 5:21 PM + */ +class TestExternalSystemLocalSettings extends AbstractExternalSystemLocalSettings { + + TestExternalSystemLocalSettings(@NotNull Project project) { + super(ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID, project) + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemManager.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemManager.groovy new file mode 100644 index 000000000000..9a4d4fe537f4 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemManager.groovy @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.execution.ExecutionException +import com.intellij.execution.configurations.SimpleJavaParameters +import com.intellij.openapi.externalSystem.ExternalSystemManager +import com.intellij.openapi.externalSystem.model.ProjectSystemId +import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver +import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager +import com.intellij.openapi.fileChooser.FileChooserDescriptor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Pair +import com.intellij.util.Function +import org.jetbrains.annotations.NotNull + +/** + * @author Denis Zhdanov + * @since 8/8/13 5:20 PM + */ +class TestExternalSystemManager implements ExternalSystemManager< +TestExternalProjectSettings, +TestExternalSystemSettingsListener, +TestExternalSystemSettings, +TestExternalSystemLocalSettings, +TestExternalSystemExecutionSettings> +{ + + TestExternalSystemSettings systemSettings + TestExternalSystemLocalSettings localSettings + TestExternalSystemExecutionSettings executionSettings + + TestExternalSystemManager(@NotNull Project project) { + systemSettings = new TestExternalSystemSettings(project) + localSettings = new TestExternalSystemLocalSettings(project) + executionSettings = new TestExternalSystemExecutionSettings() + } + + @NotNull + @Override + ProjectSystemId getSystemId() { + ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID + } + + @NotNull + @Override + Function<Project, TestExternalSystemSettings> getSettingsProvider() { { project -> systemSettings } as Function } + + @NotNull + @Override + Function<Project, TestExternalSystemLocalSettings> getLocalSettingsProvider() { { project -> localSettings } as Function } + + @NotNull + @Override + Function<Pair<Project, String>, TestExternalSystemExecutionSettings> getExecutionSettingsProvider() { + { project -> executionSettings } as Function + } + + @NotNull + @Override + Class<? extends ExternalSystemProjectResolver<TestExternalSystemExecutionSettings>> getProjectResolverClass() { + throw new UnsupportedOperationException() + } + + @Override + Class<? extends ExternalSystemTaskManager<TestExternalSystemExecutionSettings>> getTaskManagerClass() { + throw new UnsupportedOperationException() + } + + @NotNull + @Override + FileChooserDescriptor getExternalProjectDescriptor() { + throw new UnsupportedOperationException() + } + + @Override + void enhanceParameters(@NotNull @NotNull SimpleJavaParameters parameters) throws ExecutionException { + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettings.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettings.groovy new file mode 100644 index 000000000000..52bdfe5e88a7 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettings.groovy @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test + +import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListener +import com.intellij.openapi.project.Project +import org.jetbrains.annotations.NotNull +/** + * @author Denis Zhdanov + * @since 8/8/13 4:04 PM + */ +class TestExternalSystemSettings extends AbstractExternalSystemSettings< +TestExternalSystemSettings, +TestExternalProjectSettings, +TestExternalSystemSettingsListener> +{ + + TestExternalSystemSettings(Project project) { + super(ExternalSystemTestUtil.SETTINGS_TOPIC, project) + } + + @Override + void subscribe(@NotNull @NotNull ExternalSystemSettingsListener<TestExternalProjectSettings> listener) { + throw new UnsupportedOperationException() + } + + @Override + protected void copyExtraSettingsFrom(@NotNull @NotNull TestExternalSystemSettings settings) { + throw new UnsupportedOperationException() + } + + @Override + protected void checkSettings(@NotNull @NotNull TestExternalProjectSettings old, @NotNull @NotNull TestExternalProjectSettings current) { + throw new UnsupportedOperationException() + } +} diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettingsListener.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettingsListener.java new file mode 100644 index 000000000000..2128c478a1e1 --- /dev/null +++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/TestExternalSystemSettingsListener.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.externalSystem.test; + +import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListener; + +/** + * @author Denis Zhdanov + * @since 8/8/13 5:11 PM + */ +public interface TestExternalSystemSettingsListener extends ExternalSystemSettingsListener<TestExternalProjectSettings> { +} diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/CachesBasedRefSearcher.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/CachesBasedRefSearcher.java index b430c0d65095..56a2229e9fac 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/CachesBasedRefSearcher.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/CachesBasedRefSearcher.java @@ -3,7 +3,11 @@ package com.intellij.psi.impl.search; import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.SyntheticFileSystemItem; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.search.SearchScope; @@ -24,7 +28,7 @@ public class CachesBasedRefSearcher extends QueryExecutorBase<PsiReference, Refe final PsiElement refElement = p.getElementToSearch(); String text = null; - if (refElement instanceof PsiFileSystemItem) { + if (refElement instanceof PsiFileSystemItem && !(refElement instanceof SyntheticFileSystemItem)) { final VirtualFile vFile = ((PsiFileSystemItem)refElement).getVirtualFile(); if (vFile != null) { text = vFile.getNameWithoutExtension(); @@ -44,9 +48,7 @@ public class CachesBasedRefSearcher extends QueryExecutorBase<PsiReference, Refe } if (StringUtil.isNotEmpty(text)) { final SearchScope searchScope = p.getEffectiveSearchScope(); - assert text != null; p.getOptimizer().searchWord(text, searchScope, refElement.getLanguage().isCaseSensitive(), refElement); } } - -} +}
\ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/ide/projectView/ProjectViewNode.java b/platform/lang-api/src/com/intellij/ide/projectView/ProjectViewNode.java index ad18061f8750..5b72e74bcb09 100644 --- a/platform/lang-api/src/com/intellij/ide/projectView/ProjectViewNode.java +++ b/platform/lang-api/src/com/intellij/ide/projectView/ProjectViewNode.java @@ -21,19 +21,22 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; -import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * A node in the project view tree. @@ -103,23 +106,21 @@ public abstract class ProjectViewNode <Value> extends AbstractTreeNode<Value> im public static AbstractTreeNode createTreeNode(Class<? extends AbstractTreeNode> nodeClass, Project project, Object value, - ViewSettings settings) throws NoSuchMethodException, - InstantiationException, - IllegalAccessException, - InvocationTargetException { + ViewSettings settings) throws + InstantiationException { Object[] parameters = new Object[]{project, value, settings}; for (Constructor<? extends AbstractTreeNode> constructor : (Constructor<? extends AbstractTreeNode>[])nodeClass.getConstructors()) { if (constructor.getParameterTypes().length != 3) continue; try { return constructor.newInstance(parameters); } - catch (InstantiationException e) { + catch (InstantiationException ignored) { } - catch (IllegalAccessException e) { + catch (IllegalAccessException ignored) { } - catch (IllegalArgumentException e) { + catch (IllegalArgumentException ignored) { } - catch (InvocationTargetException e) { + catch (InvocationTargetException ignored) { } } throw new InstantiationException("no constructor found in " + nodeClass); @@ -142,7 +143,7 @@ public abstract class ProjectViewNode <Value> extends AbstractTreeNode<Value> im break; } - if (VfsUtil.isAncestor(eachRoot, file, true)) { + if (VfsUtilCore.isAncestor(eachRoot, file, true)) { mayContain = true; break; } @@ -191,9 +192,10 @@ public abstract class ProjectViewNode <Value> extends AbstractTreeNode<Value> im return WolfTheProblemSolver.getInstance(getProject()).hasProblemFilesBeneath(new Condition<VirtualFile>() { @Override public boolean value(final VirtualFile virtualFile) { + Value value; return contains(virtualFile) // in case of flattened packages, when package node a.b.c contains error file, node a.b might not. - && (getValue() instanceof PsiElement && Comparing.equal(PsiUtilBase.getVirtualFile((PsiElement)getValue()), virtualFile) || + && ((value = getValue()) instanceof PsiElement && Comparing.equal(PsiUtilCore.getVirtualFile((PsiElement)value), virtualFile) || someChildContainsFile(virtualFile)); } }); diff --git a/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java index 4dbbd81a4146..7b9800dbd3a2 100644 --- a/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java +++ b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java @@ -59,6 +59,11 @@ public class GotoRelatedItem { } @Nullable + public String getCustomContainerName() { + return null; + } + + @Nullable public Icon getCustomIcon() { return null; } diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java index 659f52777ed0..8f80b7fab64c 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java @@ -288,4 +288,15 @@ public class PsiUtilBase extends PsiUtilCore { final VirtualFile virtualFile = element.getVirtualFile(); return virtualFile != null && virtualFile.is(VFileProperty.SYMLINK); } + + @Nullable + public static VirtualFile asVirtualFile(@Nullable PsiElement element) { + if (element instanceof PsiFileSystemItem) { + PsiFileSystemItem psiFileSystemItem = (PsiFileSystemItem)element; + return psiFileSystemItem.isValid() ? psiFileSystemItem.getVirtualFile() : null; + } + else { + return null; + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/preview/ImagePreviewComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/preview/ImagePreviewComponent.java index 3645028717e1..3baa777939ce 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/preview/ImagePreviewComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/preview/ImagePreviewComponent.java @@ -70,6 +70,7 @@ public class ImagePreviewComponent extends JPanel implements PreviewHintComponen setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.black), BorderFactory.createEmptyBorder(5, 5, 5, 5))); } + @Override @TestOnly public boolean isEqualTo(@Nullable PreviewHintComponent other) { if (!(other instanceof ImagePreviewComponent)) { @@ -159,7 +160,7 @@ public class ImagePreviewComponent extends JPanel implements PreviewHintComponen } } } - catch (IOException e) { + catch (IOException ignored) { // nothing } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java index da2cf118495c..4aef3a91afec 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java @@ -21,7 +21,10 @@ import com.intellij.execution.configurations.*; import com.intellij.execution.runners.ProgramRunner; import com.intellij.ide.plugins.IdeaPluginDescriptorImpl; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.WriteExternalException; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -276,10 +279,10 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C for (ProgramRunner runner : myConfigurationPerRunnerSettings.keySet()) { ConfigurationPerRunnerSettings settings = myConfigurationPerRunnerSettings.get(runner); Element runnerElement = new Element(CONFIGURATION_ELEMENT); - runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); if (settings != null) { settings.writeExternal(runnerElement); } + runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); configurationPerRunnerSettings.add(runnerElement); } if (myUnloadedConfigurationPerRunnerSettings != null) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index d697943fa415..5dc26739fb5b 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -96,15 +96,6 @@ public class FindInProjectUtil { if (psiElement instanceof PsiDirectory) { directoryName = ((PsiDirectory)psiElement).getVirtualFile().getPresentableUrl(); } - else { - final PsiFile psiFile = LangDataKeys.PSI_FILE.getData(dataContext); - if (psiFile != null) { - PsiDirectory psiDirectory = psiFile.getContainingDirectory(); - if (psiDirectory != null) { - directoryName = psiDirectory.getVirtualFile().getPresentableUrl(); - } - } - } if (directoryName == null && psiElement instanceof PsiDirectoryContainer) { final PsiDirectory[] directories = ((PsiDirectoryContainer)psiElement).getDirectories(); diff --git a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java index 3a4fb08f33d8..f42623be4218 100644 --- a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java +++ b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java @@ -31,7 +31,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.util.ArrayUtil; +import com.intellij.util.ArrayUtilRt; import org.jetbrains.annotations.Nullable; import java.awt.datatransfer.DataFlavor; @@ -322,7 +322,7 @@ public class PsiCopyPasteManager { @Override public boolean isDataFlavorSupported(DataFlavor flavor) { - return ArrayUtil.find(getTransferDataFlavors(), flavor) != -1; + return ArrayUtilRt.find(getTransferDataFlavors(), flavor) != -1; } public PsiElement[] getElements() { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java index d96669d0defc..b9264d37b7bb 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java @@ -123,6 +123,11 @@ public class GotoRelatedFileAction extends AnAction { @Override public String getContainerText(PsiElement element, String name) { + String customContainerName = itemsMap.get(element).getCustomContainerName(); + + if (customContainerName != null) { + return customContainerName; + } PsiFile file = element.getContainingFile(); return file != null && !getElementText(element).equals(file.getName()) ? "(" + file.getName() + ")" diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index ab0d03419143..36f458509555 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -44,6 +44,7 @@ import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; @@ -59,6 +60,7 @@ import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.*; import com.intellij.ui.border.CustomLineBorder; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.OnOffButton; import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; @@ -222,6 +224,12 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } myAlarm.cancelAllRequests(); myList.setModel(new DefaultListModel()); + myClassModel = null; + myFileModel = null; + myActionModel = null; + myClasses = null; + myFiles = null; + myActions = null; //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { @@ -373,7 +381,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA String title = getTitle(index, value, index == 0 ? null : list.getModel().getElementAt(index -1)); myTitle.setText(title == null ? "" : title); myLeftPanel.removeAll(); - myLeftPanel.setBackground(Gray._242); + myLeftPanel.setBackground(new JBColor(Gray._242, JBColor.background())); myMainPanel.removeAll(); myLeftPanel.add(myTitle, BorderLayout.EAST); myMainPanel.add(myLeftPanel, BorderLayout.WEST); @@ -501,7 +509,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myLeftWidth += 10; myTitle.setForeground(Gray._122); myTitle.setAlignmentY(BOTTOM_ALIGNMENT); - myLeftPanel.setBorder(new CompoundBorder(new CustomLineBorder(Gray._206, 0,0,0,1), new EmptyBorder(0,0,0,5))); + myLeftPanel.setBorder(new CompoundBorder(new CustomLineBorder(new JBColor(Gray._206, Gray._75), 0,0,0,1), new EmptyBorder(0,0,0,5))); } private Font getTitleFont() { @@ -631,10 +639,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA for (MatchResult o : classes) { if (clsCounter > 15) break; - myProgressIndicator.checkCanceled(); - Object[] objects = myClassModel.getElementsByName(o.elementName, false, pattern); + + Object[] objects = myClassModel.getElementsByName(o.elementName, false, pattern, myProgressIndicator); for (Object object : objects) { - myProgressIndicator.checkCanceled(); if (!listModel.contains(object)) { listModel.addElement(object); clsCounter++; @@ -650,16 +657,13 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } for (MatchResult o : files) { if (filesCounter > 15) break; - myProgressIndicator.checkCanceled(); Object[] objects = myFileModel.getElementsByName(o.elementName, false, pattern, myProgressIndicator); for (Object object : objects) { - myProgressIndicator.checkCanceled(); if (!listModel.contains(object)) { if (object instanceof PsiFile) { object = ((PsiFile)object).getVirtualFile(); } if (object instanceof VirtualFile && !alreadyAddedFiles.contains((VirtualFile)object) && !((VirtualFile)object).isDirectory()) { - myProgressIndicator.checkCanceled(); listModel.addElement(object); filesCounter++; } @@ -767,10 +771,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myRenderer.recalculateWidth(); if (myPopup == null || !myPopup.isVisible()) { final ActionCallback callback = ListDelegationUtil.installKeyboardDelegation(field.getTextEditor(), myList); - myPopup = JBPopupFactory.getInstance() - .createListPopupBuilder(myList) - .setRequestFocus(false) - .createPopup(); + final PopupChooserBuilder builder = JBPopupFactory.getInstance().createListPopupBuilder(myList); + myPopup = builder.setRequestFocus(false).createPopup(); Disposer.register(myPopup, new Disposable() { @Override public void dispose() { @@ -793,7 +795,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myPopup.cancel(); } else { final Dimension size = myList.getPreferredSize(); - myPopup.setSize(new Dimension(Math.min(600, Math.max(field.getWidth(), size.width + 15)), Math.min(600, size.height + 10))); + Dimension sz = new Dimension(Math.max(field.getWidth(), size.width), size.height); + if (sz.width > 800 || sz.height > 800) { + final int extra = new JBScrollPane().getVerticalScrollBar().getWidth(); + sz = new Dimension(Math.min(800, Math.max(field.getWidth(), size.width + extra)), Math.min(800, size.height + extra)); + sz.width += 16; + } else { + sz.height++; + sz.height++; + sz.width++; + sz.width++; + } + myPopup.setSize(sz); final Point screen = field.getLocationOnScreen(); final int x = screen.x + field.getWidth() - myPopup.getSize().width; @@ -823,7 +836,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA MatchResult result; for (String name : names) { - myProgressIndicator.checkCanceled(); + //myProgressIndicator.checkCanceled(); result = null; if (model instanceof CustomMatcherModel) { try { diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarUpdateQueue.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarUpdateQueue.java index e9e0e127d6e3..297334710c06 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarUpdateQueue.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarUpdateQueue.java @@ -117,7 +117,9 @@ public class NavBarUpdateQueue extends MergingUpdateQueue { void restartRebuild() { myUserActivityAlarm.cancelAllRequests(); - myUserActivityAlarm.addRequest(myUserActivityAlarmRunnable, Registry.intValue("navBar.userActivityMergeTime")); + if (!myUserActivityAlarm.isDisposed()) { + myUserActivityAlarm.addRequest(myUserActivityAlarmRunnable, Registry.intValue("navBar.userActivityMergeTime")); + } } private void processUserActivity() { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/BaseProjectTreeBuilder.java b/platform/lang-impl/src/com/intellij/ide/projectView/BaseProjectTreeBuilder.java index 5f4d6d903cb6..2302c23fd5f4 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/BaseProjectTreeBuilder.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/BaseProjectTreeBuilder.java @@ -34,7 +34,8 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,26 +69,15 @@ public abstract class BaseProjectTreeBuilder extends AbstractTreeBuilder { if (element instanceof AbstractTreeNode) { AbstractTreeNode node = (AbstractTreeNode)element; final Object value = node.getValue(); - VirtualFile vFile = null; - if (value instanceof PsiFileSystemItem) { - vFile = ((PsiFileSystemItem)value).getVirtualFile(); - } - else if (value instanceof PsiElement) { - PsiFile psiFile = ((PsiElement)value).getContainingFile(); - if (psiFile != null) { - vFile = psiFile.getVirtualFile(); - } - } - final ActionCallback cb = new ActionCallback(); - - final VirtualFile finalVFile = vFile; + final ActionCallback callback = new ActionCallback(); + final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(ObjectUtils.tryCast(value, PsiElement.class)); final FocusRequestor focusRequestor = IdeFocusManager.getInstance(myProject).getFurtherRequestor(); batch(new Progressive() { @Override public void run(@NotNull ProgressIndicator indicator) { final Ref<Object> target = new Ref<Object>(); - _select(value, finalVFile, false, Conditions.<AbstractTreeNode>alwaysTrue(), cb, indicator, target, focusRequestor, false); - cb.doWhenDone(new Runnable() { + _select(value, virtualFile, false, Conditions.<AbstractTreeNode>alwaysTrue(), callback, indicator, target, focusRequestor, false); + callback.doWhenDone(new Runnable() { @Override public void run() { result.setDone(target.get()); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewTree.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewTree.java index 38f74c34ec73..9341e52f00db 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewTree.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewTree.java @@ -31,12 +31,10 @@ import com.intellij.ui.JBTreeWithHintProvider; import com.intellij.ui.tabs.FileColorManagerImpl; import com.intellij.util.Function; import com.intellij.util.NullableFunction; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.plaf.ColorUIResource; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeModel; import java.awt.*; @@ -85,13 +83,13 @@ public abstract class ProjectViewTree extends JBTreeWithHintProvider { return super.getToggleClickCount(); } - @Override - public Color getBackground() { - if (!UIUtil.isUnderDarcula()) { - return super.getBackground(); - } - return new ColorUIResource(0x414750); - } + //@Override + //public Color getBackground() { + // if (!UIUtil.isUnderDarcula()) { + // return super.getBackground(); + // } + // return new ColorUIResource(0x414750); + //} @Override public boolean isFileColorsEnabled() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index a641ada5d996..ac492d5f6976 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -790,8 +790,15 @@ public abstract class ChooseByNameBase { ownerWindow.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } } - myNames[index] = myModel.getNames(checkboxState); - assert myNames[index] != null : "Model "+myModel+ "("+myModel.getClass()+") returned null names"; + + if (index == 1 && myModel instanceof ContributorsBasedGotoByModel) { + // there is no way in indices to have different keys for project symbols vs libraries, we always have same ones + myNames[1] = myNames[0]; + return; + } else { + myNames[index] = myModel.getNames(checkboxState); + assert myNames[index] != null : "Model "+myModel+ "("+myModel.getClass()+") returned null names"; + } if (window != null) { window.setCursor(Cursor.getDefaultCursor()); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java index 2ac6e3230b60..f87ccd617059 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java @@ -217,4 +217,8 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModel public boolean useMiddleMatching() { return true; } + + public @NotNull String removeModelSpecificMarkup(@NotNull String pattern) { + return pattern; + } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java index b97bacae4236..5b965cc379f8 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java @@ -148,7 +148,11 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider final String[] separators = base.getModel().getSeparators(); int lastSeparatorOccurrence = 0; for (String separator : separators) { - lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, pattern.lastIndexOf(separator)); + int idx = pattern.lastIndexOf(separator); + if (idx == pattern.length() - 1) { // avoid empty name + idx = pattern.lastIndexOf(separator, idx - 1); + } + lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, idx); } return pattern.substring(0, lastSeparatorOccurrence); } @@ -161,7 +165,10 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider final String[] separators = model.getSeparators(); int lastSeparatorOccurrence = 0; for (String separator : separators) { - final int idx = pattern.lastIndexOf(separator); + int idx = pattern.lastIndexOf(separator); + if (idx == pattern.length() - 1) { // avoid empty name + idx = pattern.lastIndexOf(separator, idx - 1); + } lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, idx == -1 ? idx : idx + separator.length()); } @@ -294,8 +301,9 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider @NotNull private static String removeModelSpecificMarkup(@NotNull ChooseByNameBase base, @NotNull String pattern) { - if (base.getModel() instanceof GotoClassModel2 && pattern.startsWith("@")) { - pattern = pattern.substring(1); + ChooseByNameModel model = base.getModel(); + if (model instanceof ContributorsBasedGotoByModel) { + pattern = ((ContributorsBasedGotoByModel)model).removeModelSpecificMarkup(pattern); } return pattern; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultFileNavigationContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultFileNavigationContributor.java index 2753d96b29ec..8bb113356df6 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultFileNavigationContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultFileNavigationContributor.java @@ -34,7 +34,9 @@ public class DefaultFileNavigationContributor implements ChooseByNameContributor @Override @NotNull public NavigationItem[] getItemsByName(String name, final String pattern, Project project, boolean includeNonProjectItems) { + final boolean includeDirs = pattern.endsWith("/") || pattern.endsWith("\\"); return FilenameIndex.getFilesByName(project, name, - includeNonProjectItems ? ProjectScope.getAllScope(project) : ProjectScope.getProjectScope(project), true); + includeNonProjectItems ? ProjectScope.getAllScope(project) : ProjectScope.getProjectScope(project), + includeDirs); } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java index f10ec0dd4be9..329c190b2cda 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java @@ -135,6 +135,13 @@ public class GotoClassModel2 extends FilteringGotoByModel<Language> { return "procedures.navigating.goto.class"; } + @NotNull + @Override + public String removeModelSpecificMarkup(@NotNull String pattern) { + if (pattern.startsWith("@")) return pattern.substring(1); + return pattern; + } + @Override public boolean willOpenEditor() { return true; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoFileModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoFileModel.java index 220499365217..adc943ea17bc 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoFileModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoFileModel.java @@ -140,4 +140,13 @@ public class GotoFileModel extends FilteringGotoByModel<FileType> { public boolean willOpenEditor() { return true; } + + @NotNull + @Override + public String removeModelSpecificMarkup(@NotNull String pattern) { + if ((pattern.endsWith("/") || pattern.endsWith("\\"))) { + return pattern.substring(0, pattern.length() - 1); + } + return pattern; + } }
\ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java b/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java index c7f8c90a3e88..e52bb4ba5f74 100644 --- a/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java +++ b/platform/platform-api/src/com/intellij/util/ui/update/MergingUpdateQueue.java @@ -58,11 +58,11 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { private boolean myTrackUiActivity; private UiActivity myUiActivity; - public MergingUpdateQueue(@NonNls String name, int mergingTimeSpan, boolean isActive, JComponent modalityStateComponent) { + public MergingUpdateQueue(@NonNls @NotNull String name, int mergingTimeSpan, boolean isActive, @Nullable JComponent modalityStateComponent) { this(name, mergingTimeSpan, isActive, modalityStateComponent, null); } - public MergingUpdateQueue(@NonNls String name, + public MergingUpdateQueue(@NonNls @NotNull String name, int mergingTimeSpan, boolean isActive, @Nullable JComponent modalityStateComponent, @@ -70,7 +70,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { this(name, mergingTimeSpan, isActive, modalityStateComponent, parent, null); } - public MergingUpdateQueue(@NonNls String name, + public MergingUpdateQueue(@NonNls @NotNull String name, int mergingTimeSpan, boolean isActive, @Nullable JComponent modalityStateComponent, @@ -79,7 +79,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { this(name, mergingTimeSpan, isActive, modalityStateComponent, parent, activationComponent, true); } - public MergingUpdateQueue(@NonNls String name, + public MergingUpdateQueue(@NonNls @NotNull String name, int mergingTimeSpan, boolean isActive, @Nullable JComponent modalityStateComponent, @@ -90,7 +90,7 @@ public class MergingUpdateQueue implements Runnable, Disposable, Activatable { executeInDispatchThread ? Alarm.ThreadToUse.SWING_THREAD : Alarm.ThreadToUse.POOLED_THREAD); } - public MergingUpdateQueue(@NonNls String name, + public MergingUpdateQueue(@NonNls @NotNull String name, int mergingTimeSpan, boolean isActive, @Nullable JComponent modalityStateComponent, diff --git a/platform/platform-impl/src/com/intellij/execution/ExecutableValidator.java b/platform/platform-impl/src/com/intellij/execution/ExecutableValidator.java index 7e4257b128d7..45af015a84ab 100644 --- a/platform/platform-impl/src/com/intellij/execution/ExecutableValidator.java +++ b/platform/platform-impl/src/com/intellij/execution/ExecutableValidator.java @@ -91,7 +91,8 @@ public abstract class ExecutableValidator { CapturingProcessHandler handler = new CapturingProcessHandler(commandLine.createProcess(), CharsetToolkit.getDefaultSystemCharset()); ProcessOutput result = handler.runProcess(60 * 1000); return !result.isTimeout() && (result.getExitCode() == 0) && result.getStderr().isEmpty(); - } catch (Throwable e) { + } + catch (Throwable ignored) { return false; } } @@ -199,14 +200,12 @@ public abstract class ExecutableValidator { private class ExecutableNotValidNotification extends Notification { private ExecutableNotValidNotification() { - super(myNotificationGroup.getDisplayId(), "", prepareDescription(), NotificationType.ERROR, new NotificationListener() { - public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { - if (event.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { - showSettingsAndExpireIfFixed(notification); - } + super(myNotificationGroup.getDisplayId(), "", prepareDescription(), NotificationType.ERROR, new NotificationListener.Adapter() { + @Override + protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + showSettingsAndExpireIfFixed(notification); } }); } } - -} +}
\ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java b/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java index 8e4f6a20e703..de780548e715 100644 --- a/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/XmlRpcServerImpl.java @@ -106,7 +106,7 @@ public class XmlRpcServerImpl implements XmlRpcServer { HttpResponse response = Responses.create("text/xml"); response.setContent(result); - Responses.send(response, request, context); + Responses.send(response, context.getChannel(), request); return true; } else if (HttpMethod.POST.getName().equals(request.getHeader("Access-Control-Request-Method"))) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java index cf6fa612f360..e77c33388d63 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java @@ -47,6 +47,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.ShowSettingsUtilImpl"); private AtomicBoolean myShown = new AtomicBoolean(false); + @Override public void showSettingsDialog(Project project, ConfigurableGroup[] group) { try { myShown.set(true); @@ -73,6 +74,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { } } + @Override public void showSettingsDialog(@Nullable final Project project, final Class configurableClass) { assert Configurable.class.isAssignableFrom(configurableClass) : "Not a configurable: " + configurableClass.getName(); @@ -97,6 +99,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { return null; } + @Override public void showSettingsDialog(@Nullable final Project project, @NotNull final String nameToSelect) { ConfigurableGroup[] group; if (project == null) { @@ -176,6 +179,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { return null; } + @Override public void showSettingsDialog(@NotNull final Project project, final Configurable toSelect) { _showSettingsDialog(project, new ConfigurableGroup[]{ new ProjectConfigurablesGroup(project), @@ -193,30 +197,37 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { return groups.toArray(new ConfigurableGroup[groups.size()]); } + @Override public boolean editConfigurable(Project project, Configurable configurable) { return editConfigurable(project, createDimensionKey(configurable), configurable); } + @Override public <T extends Configurable> T findApplicationConfigurable(final Class<T> confClass) { return ConfigurableExtensionPointUtil.findApplicationConfigurable(confClass); } + @Override public <T extends Configurable> T findProjectConfigurable(final Project project, final Class<T> confClass) { return ConfigurableExtensionPointUtil.findProjectConfigurable(project, confClass); } + @Override public boolean editConfigurable(Project project, String dimensionServiceKey, @NotNull Configurable configurable) { return editConfigurable(null, project, configurable, dimensionServiceKey, null); } + @Override public boolean editConfigurable(Project project, Configurable configurable, Runnable advancedInitialization) { return editConfigurable(null, project, configurable, createDimensionKey(configurable), advancedInitialization); } + @Override public boolean editConfigurable(Component parent, Configurable configurable) { return editConfigurable(parent, configurable, null); } + @Override public boolean editConfigurable(final Component parent, final Configurable configurable, @Nullable final Runnable advancedInitialization) { return editConfigurable(parent, null, configurable, createDimensionKey(configurable), advancedInitialization); } @@ -248,6 +259,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { return "#" + displayName; } + @Override public boolean editConfigurable(Component parent, String dimensionServiceKey,Configurable configurable) { return editConfigurable(parent, null, configurable, dimensionServiceKey, null); } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index 555ad5a7e954..5922749915bf 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -104,10 +104,10 @@ SplitPane.highlight=3c3f41 Hyperlink.linkColor=589df6 -List.background=45494A -Table.background=45494A +#List.background=45494A +#Table.background=45494A -Tree.background=45494A +#Tree.background=45494A Tree.collapsedIcon=AllIcons.Mac.Tree_white_right_arrow Tree.expandedIcon=AllIcons.Mac.Tree_white_down_arrow diff --git a/platform/platform-impl/src/com/intellij/idea/SocketLock.java b/platform/platform-impl/src/com/intellij/idea/SocketLock.java index 149de23f8e46..ceddbd18d97f 100644 --- a/platform/platform-impl/src/com/intellij/idea/SocketLock.java +++ b/platform/platform-impl/src/com/intellij/idea/SocketLock.java @@ -79,6 +79,12 @@ public class SocketLock { } } + private volatile int acquiredPort = -1; + + public synchronized int getAcquiredPort () { + return acquiredPort; + } + public synchronized ActivateStatus lock(String path, boolean markPort, String... args) { if (LOG.isDebugEnabled()) { LOG.debug("enter: lock(path='" + path + "')"); @@ -194,6 +200,7 @@ public class SocketLock { mySocket = new ServerSocket(i, 50, InetAddress.getByName("127.0.0.1")); port = i; + acquiredPort = port; break; } catch (IOException e) { diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index 7b01b1874695..5aed4ed72cd7 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -76,6 +76,10 @@ public class StartupUtil { void start(boolean newConfigFolder); } + public synchronized static int getAcquiredPort() { + return ourLock.getAcquiredPort(); + } + static void prepareAndStart(String[] args, AppStarter appStarter) { boolean newConfigFolder = false; diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index eec201a44892..5e4633b93d9d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -336,7 +336,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application return false; } } - ApplicationManager.getApplication().runWriteAction(new Runnable() { + runWriteAction(new Runnable() { @Override public void run() { Disposer.dispose(ApplicationImpl.this); @@ -636,8 +636,9 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application assertIsDispatchThread(); if (myExceptionalThreadWithReadAccessRunnable != null || - ApplicationManager.getApplication().isUnitTestMode() || - ApplicationManager.getApplication().isHeadlessEnvironment()) { + isUnitTestMode() || + isHeadlessEnvironment() + ) { try { ProgressManager.getInstance().runProcess(process, new EmptyProgressIndicator()); } @@ -653,7 +654,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application try { myExceptionalThreadWithReadAccessRunnable = process; - final boolean[] threadStarted = {false}; + final AtomicBoolean threadStarted = new AtomicBoolean(); //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { @Override @@ -688,13 +689,13 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } } }); - threadStarted[0] = true; + threadStarted.set(true); } }); progress.startBlocking(); - LOG.assertTrue(threadStarted[0]); + LOG.assertTrue(threadStarted.get()); LOG.assertTrue(!progress.isRunning()); } finally { @@ -801,7 +802,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application * Note: there are possible scenarios when we get a quit notification at a moment when another * quit message is shown. In that case, showing multiple messages sounds contra-intuitive as well */ - private volatile static boolean exiting = false; + private static volatile boolean exiting = false; public void exit(final boolean force, final boolean allowListenersToCancel, final boolean restart) { @@ -1109,7 +1110,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application assertIsDispatchThread("Access is allowed from event dispatch thread only."); } - private static void assertIsDispatchThread(String message) { + private static void assertIsDispatchThread(@NotNull String message) { final Thread currentThread = Thread.currentThread(); if (ourDispatchThread == currentThread) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java index 9a066058f8ee..827896f46ae8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java @@ -61,7 +61,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { final StateSplitter splitter, Disposable parentDisposable, final PicoContainer picoContainer) { - assert dir.indexOf("$") < 0; + assert !dir.contains("$") : dir; myPathMacroSubstitutor = pathMacroSubstitutor; myDir = FILE_SYSTEM.createFile(dir); mySplitter = splitter; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java index ab3a415a01b3..10806743593c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/SystemDock.java @@ -16,7 +16,9 @@ package com.intellij.openapi.wm.impl; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.mac.MacDockDelegate; +import com.intellij.ui.win.WinDockDelegate; /** * @author Denis Fokin @@ -28,6 +30,8 @@ public class SystemDock { static { if (SystemInfo.isMac) { delegate = MacDockDelegate.getInstance(); + } else if (SystemInfo.isWin7OrNewer && Registry.is("windows.jumplist")) { + delegate = WinDockDelegate.getInstance(); } } @@ -36,7 +40,7 @@ public class SystemDock { delegate.updateRecentProjectsMenu(); } - public static interface Delegate { + public interface Delegate { void updateRecentProjectsMenu(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ContentTabLabel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ContentTabLabel.java index 06750e5c69a7..7eebc674c8b0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ContentTabLabel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ContentTabLabel.java @@ -71,18 +71,18 @@ class ContentTabLabel extends BaseLabel { @Override protected Color getActiveFg(boolean selected) { - if (contentManager().getContentCount() > 1 && selected) { - return Gray._255; - } - return super.getActiveFg(selected); + if (contentManager().getContentCount() > 1) { + return selected ? Color.white : UIUtil.isUnderDarcula() ? UIUtil.getLabelForeground() : Color.black; + } + return super.getActiveFg(selected); } @Override protected Color getPassiveFg(boolean selected) { - if (contentManager().getContentCount() > 1 && selected && !UIUtil.isUnderDarcula()) { - return Gray._255; - } - return super.getPassiveFg(selected); + if (contentManager().getContentCount() > 1) { + return selected && !UIUtil.isUnderDarcula() ? Gray._255 : UIUtil.isUnderDarcula()? UIUtil.getLabelDisabledForeground() : Gray._75; + } + return super.getPassiveFg(selected); } protected void paintComponent(final Graphics g) { diff --git a/platform/platform-impl/src/com/intellij/platform/WebProjectGenerator.java b/platform/platform-impl/src/com/intellij/platform/WebProjectGenerator.java index 2707d508fac7..ec5889062b20 100644 --- a/platform/platform-impl/src/com/intellij/platform/WebProjectGenerator.java +++ b/platform/platform-impl/src/com/intellij/platform/WebProjectGenerator.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; /** * Extend this class to contribute web project generator to IDEA (available via File -> 'Add Module...' -> 'Web Module') @@ -47,6 +48,11 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato public abstract String getDescription(); @Nullable + public Integer getPreferredDescriptionWidth() { + return null; + } + + @Nullable public String getHelpId() { return null; } @@ -114,7 +120,22 @@ public abstract class WebProjectGenerator<T> implements DirectoryProjectGenerato super(true); myPeer = peer; myCenterComponent = peer.getComponent(); - myDescriptionPane = new JTextPane(); + final Integer preferredDescriptionWidth = getPreferredDescriptionWidth(); + if (preferredDescriptionWidth == null) { + myDescriptionPane = new JTextPane(); + } + else { + myDescriptionPane = new JTextPane() { + @Override + public Dimension getPreferredSize() { + // This trick makes text component to carry text over to the next line + // iff the text line width exceeds parent's width + Dimension dimension = super.getPreferredSize(); + dimension.width = preferredDescriptionWidth; + return dimension; + } + }; + } myDescriptionPane.setBorder(IdeBorderFactory.createEmptyBorder(5, 0, 10, 0)); Messages.configureMessagePaneUi(myDescriptionPane, getDescription()); diff --git a/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java new file mode 100644 index 000000000000..2d620b1a750d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ui.win; + +import com.intellij.openapi.application.PathManager; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.concurrent.atomic.AtomicBoolean; + +public class RecentTasks { + + private static AtomicBoolean initialiazed = + new AtomicBoolean(false); + + private final static WeakReference<Thread> openerThread = + new WeakReference<Thread>(Thread.currentThread()); + + static { + final String libraryName = (System.getProperty("sun.arch.data.model").contains("64"))? + "jumplistbridge64.dll": + "jumplistbridge.dll"; + + final String binPath = PathManager.getBinPath(); + final String communityBinPath = PathManager.getHomePath() + File.separatorChar + "community" + File.separatorChar + "bin"; + + final String [] libraryPaths = { + binPath, + binPath + File.separatorChar + "win", + communityBinPath, + communityBinPath + File.separatorChar + "win", + }; + + for (String path : libraryPaths) { + final File candidate = new File(path + File.separatorChar + libraryName); + if (candidate.exists()) { + System.load(candidate.getAbsolutePath()); + break; + } + } + } + + private synchronized static void init() { + if (initialiazed.get()) return; + + initialize("JetBrains.JetBrainsNativeAppID"); + initialiazed.set(true); + } + + /** + * Com initialization should be invoked once per process. + * All invocation should be made from the same thread. + * @param applicationId + */ + native private static void initialize (String applicationId); + native private static void addTaskNative (String location, String args, String description); + native private static void clearNative(); + + public synchronized static void clear() { + init(); + checkThread(); + clearNative(); + } + + public synchronized static void addTask(File location, String args, String description) { + init(); + checkThread(); + if (!location.exists()) throw new IllegalArgumentException("Task should be a valid path"); + addTaskNative(location.getAbsolutePath(), args, description); + } + + private static void checkThread() { + Thread t = openerThread.get(); + if (t == null || !t.equals(Thread.currentThread())) + throw new RuntimeException("This class has to be used from the same thread"); + } +} + diff --git a/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java b/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java new file mode 100644 index 000000000000..84372bf5c9cd --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/SocketControlHelper.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ui.win; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * @author Denis Fokin + */ +public class SocketControlHelper { + + private static final String ACTIVATE_COMMAND = "activate "; + + /* + * args[0] - socket of controlled IDE + * args[1] - project path + */ + public static void main(String[] args) { + final int portNumber = Integer.parseInt(args[0]); + final String pathToProject = new File(args[1]).getAbsolutePath(); + final InetAddress lba = getLoopbackAddress(); + + try { + Socket socket = new Socket(lba, portNumber); + socket.setSoTimeout(300); + DataInputStream in = new DataInputStream(socket.getInputStream()); + DataOutputStream out = new DataOutputStream(socket.getOutputStream()); + try { + + out.writeUTF(ACTIVATE_COMMAND + new File(".").getAbsolutePath() + "\0" + pathToProject); + out.flush(); + String response = in.readUTF(); + if (response.equals("ok")) { + System.err.println("Activated."); + } + } finally { + in.close(); + out.close(); + socket.close(); + } + } catch (IOException ignored) {} + + System.err.println("Activation failed"); + } + + private static InetAddress getLoopbackAddress() { + InetAddress returnValue = null; + try { + returnValue = InetAddress.getByName("127.0.0.1"); + } catch (UnknownHostException uhe) { + uhe.printStackTrace(); + } + return returnValue; + } +} diff --git a/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java b/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java new file mode 100644 index 000000000000..951154f909ff --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/win/WinDockDelegate.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ui.win; + +import com.intellij.ide.RecentProjectsManagerBase; +import com.intellij.ide.ReopenProjectAction; +import com.intellij.idea.StartupUtil; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.wm.impl.SystemDock; +import java.io.File; + +/** + * @author Denis Fokin + */ +public class WinDockDelegate implements SystemDock.Delegate { + + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.win.WinDockDelegate"); + + private static final String javaExe = System.getProperty("java.home") + File.separatorChar + "bin" + File.separatorChar + "javaw.exe"; + private static final String argsToExecute = new StringBuilder(" -classpath ").append(PathManager.getJarPathForClass(SocketControlHelper.class)). + append(" com.intellij.ui.win.SocketControlHelper ").append(StartupUtil.getAcquiredPort()) + .append(" ").toString(); + + private static boolean initialized = false; + private static final SystemDock.Delegate instance = new WinDockDelegate(); + + private WinDockDelegate() {} + + public void updateRecentProjectsMenu () { + final AnAction[] recentProjectActions = RecentProjectsManagerBase.getInstance().getRecentProjectsActions(false); + RecentTasks.clear(); + for (final AnAction action : recentProjectActions) { + ReopenProjectAction rpa = ((ReopenProjectAction)action); + RecentTasks.addTask(new File(javaExe), argsToExecute + rpa.getProjectPath(), rpa.getProjectName()); + } + } + synchronized public static SystemDock.Delegate getInstance() { + if (!initialized) { + initialized = true; + } + return instance; + } +} diff --git a/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandlerBase.java b/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandlerBase.java index 72e68ceb95be..7fd497bb710c 100644 --- a/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandlerBase.java +++ b/platform/platform-impl/src/org/jetbrains/io/DelegatingHttpRequestHandlerBase.java @@ -38,7 +38,7 @@ abstract class DelegatingHttpRequestHandlerBase extends SimpleChannelUpstreamHan //} if (!process(context, request, new QueryStringDecoder(request.getUri()))) { - Responses.sendStatus(request, context, NOT_FOUND); + Responses.sendStatus(request, context.getChannel(), NOT_FOUND); } } diff --git a/platform/platform-impl/src/org/jetbrains/io/FileResponses.java b/platform/platform-impl/src/org/jetbrains/io/FileResponses.java index 35db7720af04..9573311f96b3 100644 --- a/platform/platform-impl/src/org/jetbrains/io/FileResponses.java +++ b/platform/platform-impl/src/org/jetbrains/io/FileResponses.java @@ -45,7 +45,7 @@ public class FileResponses { return response; } - private static boolean checkCache(HttpRequest request, ChannelHandlerContext context, long lastModified) { + private static boolean checkCache(HttpRequest request, Channel channel, long lastModified) { String ifModifiedSince = request.getHeader(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { try { @@ -54,7 +54,7 @@ public class FileResponses { addAllowAnyOrigin(response); addDate(response); addServer(response); - send(response, request, context); + send(response, channel, request); return true; } } @@ -66,8 +66,8 @@ public class FileResponses { return false; } - public static void sendFile(HttpRequest request, ChannelHandlerContext context, File file) throws IOException { - if (checkCache(request, context, file.lastModified())) { + public static void sendFile(HttpRequest request, Channel channel, File file) throws IOException { + if (checkCache(request, channel, file.lastModified())) { return; } @@ -83,7 +83,6 @@ public class FileResponses { setContentLength(response, fileLength); } - Channel channel = context.getChannel(); ChannelFuture future = channel.write(response); if (request.getMethod() != HttpMethod.HEAD) { diff --git a/platform/platform-impl/src/org/jetbrains/io/Responses.java b/platform/platform-impl/src/org/jetbrains/io/Responses.java index 4e2fdfefe97d..55f603a22c40 100644 --- a/platform/platform-impl/src/org/jetbrains/io/Responses.java +++ b/platform/platform-impl/src/org/jetbrains/io/Responses.java @@ -158,16 +158,16 @@ public final class Responses { } } - public static void sendStatus(HttpRequest request, ChannelHandlerContext context, HttpResponseStatus responseStatus) { - sendStatus(request, context, responseStatus, null); + public static void sendStatus(HttpRequest request, Channel channel, HttpResponseStatus responseStatus, @Nullable String description) { + sendStatus(new DefaultHttpResponse(HTTP_1_1, responseStatus), request, channel, description); } - public static void sendStatus(HttpRequest request, ChannelHandlerContext context, HttpResponseStatus responseStatus, @Nullable String description) { - sendStatus(new DefaultHttpResponse(HTTP_1_1, responseStatus), request, context.getChannel(), description); + public static void sendStatus(HttpRequest request, Channel channel, HttpResponseStatus responseStatus) { + sendStatus(request, channel, responseStatus, null); } - public static void sendStatus(HttpResponse response, HttpRequest request, ChannelHandlerContext context) { - sendStatus(response, request, context.getChannel(), null); + public static void sendStatus(HttpResponse response, HttpRequest request, Channel channel) { + sendStatus(response, request, channel, null); } public static void sendStatus(HttpResponseStatus responseStatus, Channel channel) { @@ -198,4 +198,4 @@ public final class Responses { response.setHeader(ALLOW, allowHeaders); send(response, request, context); } -} +}
\ No newline at end of file diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index e47727594891..876919883124 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -307,3 +307,7 @@ ide.mac.message.sheets.java.emulation=false ide.mac.message.sheets.java.emulation.description=Use Java message sheets instead of native ones linux.native.menu=false linux.native.menu.description=Enables native menu on Ubuntu +windows.jumplist=false +windows.jumplist.description=Enables JumpLists on Windows + +external.system.in.process=false
\ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml index 77257eb660af..f2f4435534ed 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml @@ -5,6 +5,8 @@ <!--Generic services--> <applicationService serviceImplementation="com.intellij.openapi.externalSystem.service.ExternalSystemFacadeManager"/> + <applicationService serviceImplementation="com.intellij.openapi.externalSystem.service.RemoteExternalSystemCommunicationManager"/> + <applicationService serviceImplementation="com.intellij.openapi.externalSystem.service.InProcessExternalSystemCommunicationManager"/> <applicationService serviceInterface="com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager" serviceImplementation="com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl"/> diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/configuration/RemoteServerListener.java b/platform/remote-servers/api/src/com/intellij/remoteServer/configuration/RemoteServerListener.java new file mode 100644 index 000000000000..894fb4ab7754 --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/configuration/RemoteServerListener.java @@ -0,0 +1,16 @@ +package com.intellij.remoteServer.configuration; + +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; + +/** + * @author nik + */ +public interface RemoteServerListener extends EventListener { + Topic<RemoteServerListener> TOPIC = Topic.create("remote servers", RemoteServerListener.class); + + void serverAdded(@NotNull RemoteServer<?> server); + void serverRemoved(@NotNull RemoteServer<?> server); +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java index eedc054413d8..60265e802850 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java @@ -1,8 +1,14 @@ package com.intellij.remoteServer.runtime; +import com.intellij.openapi.util.text.StringUtil; + /** * @author nik */ public enum ConnectionStatus { - DISCONNECTED, CONNECTED, CONNECTING, DISCONNECTING + DISCONNECTED, CONNECTED, CONNECTING, DISCONNECTING; + + public String getPresentableText() { + return StringUtil.capitalize(name().toLowerCase()); + } } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java new file mode 100644 index 000000000000..fe0f09a866fb --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java @@ -0,0 +1,23 @@ +package com.intellij.remoteServer.runtime; + +import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime; +import com.intellij.remoteServer.runtime.deployment.DeploymentStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public interface Deployment { + @NotNull + String getName(); + + @NotNull + DeploymentStatus getStatus(); + + @NotNull + String getStatusText(); + + @Nullable + DeploymentRuntime getRuntime(); +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java index a73037bc80fb..f78921e2272d 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java @@ -2,11 +2,11 @@ package com.intellij.remoteServer.runtime; import com.intellij.remoteServer.configuration.RemoteServer; import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration; -import com.intellij.remoteServer.configuration.deployment.DeploymentSource; -import com.intellij.remoteServer.runtime.deployment.DeploymentStatus; import com.intellij.remoteServer.runtime.deployment.DeploymentTask; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + /** * @author nik */ @@ -26,8 +26,8 @@ public interface ServerConnection<D extends DeploymentConfiguration> { void deploy(@NotNull DeploymentTask<D> task); - void undeploy(@NotNull DeploymentTask<D> task); + void computeDeployments(@NotNull Runnable onFinished); @NotNull - DeploymentStatus getDeploymentStatus(@NotNull DeploymentSource source); + Collection<Deployment> getDeployments(); } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionListener.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionListener.java new file mode 100644 index 000000000000..b49c4dc08222 --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionListener.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.remoteServer.runtime; + +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; + +/** + * @author nik + */ +public interface ServerConnectionListener extends EventListener { + Topic<ServerConnectionListener> TOPIC = Topic.create("server connections", ServerConnectionListener.class); + + void onConnectionCreated(@NotNull ServerConnection<?> connection); + + void onConnectionStatusChanged(@NotNull ServerConnection<?> connection); + + void onDeploymentsChanged(@NotNull ServerConnection<?> connection); +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionManager.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionManager.java index 494504c68062..d174218be244 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionManager.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnectionManager.java @@ -4,6 +4,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.remoteServer.configuration.RemoteServer; import com.intellij.remoteServer.configuration.ServerConfiguration; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -19,6 +20,9 @@ public abstract class ServerConnectionManager { @NotNull public abstract <C extends ServerConfiguration> ServerConnection getOrCreateConnection(@NotNull RemoteServer<C> server); + @Nullable + public abstract <C extends ServerConfiguration> ServerConnection getConnection(@NotNull RemoteServer<C> server); + @NotNull public abstract Collection<ServerConnection> getConnections(); } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java new file mode 100644 index 000000000000..6bae6c8739c6 --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java @@ -0,0 +1,20 @@ +package com.intellij.remoteServer.runtime.deployment; + +import com.intellij.remoteServer.runtime.RemoteOperationCallback; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class DeploymentRuntime { + public boolean isUndeploySupported() { + return false; + } + + public void undeploy(@NotNull UndeploymentTaskCallback callback) { + } + + public interface UndeploymentTaskCallback extends RemoteOperationCallback { + void succeeded(); + } +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java index 48908c4cc4e3..a9f7c285ebdb 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java @@ -1,8 +1,19 @@ package com.intellij.remoteServer.runtime.deployment; +import org.jetbrains.annotations.NotNull; + /** * @author nik */ public enum DeploymentStatus { - DEPLOYED, NOT_DEPLOYED, DEPLOYING, UNDEPLOYING + DEPLOYED("Deployed"), NOT_DEPLOYED("Not deployed"), DEPLOYING("Deploying"), UNDEPLOYING("Undeploying"); + private String myPresentableText; + + DeploymentStatus(@NotNull String presentableText) { + myPresentableText = presentableText; + } + + public String getPresentableText() { + return myPresentableText; + } } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java index 2d0e08e7de18..05c4bdcdb2d0 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java @@ -1,9 +1,13 @@ package com.intellij.remoteServer.runtime.deployment; import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration; +import com.intellij.remoteServer.configuration.deployment.DeploymentSource; +import com.intellij.remoteServer.runtime.Deployment; import com.intellij.remoteServer.runtime.RemoteOperationCallback; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * @author nik */ @@ -11,9 +15,18 @@ public abstract class ServerRuntimeInstance<D extends DeploymentConfiguration> { public abstract void deploy(@NotNull DeploymentTask<D> task, @NotNull DeploymentOperationCallback callback); - public abstract void undeploy(@NotNull DeploymentTask<D> task, @NotNull DeploymentOperationCallback callback); + public abstract void computeDeployments(@NotNull ComputeDeploymentsCallback deployments); + + @NotNull + public String getDeploymentName(@NotNull DeploymentSource source) { + return source.getPresentableName(); + } public interface DeploymentOperationCallback extends RemoteOperationCallback { - void succeeded(); + void succeeded(@NotNull DeploymentRuntime deployment); + } + + public interface ComputeDeploymentsCallback extends RemoteOperationCallback { + void succeeded(@NotNull List<Deployment> deployments); } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServersManagerImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServersManagerImpl.java index 15199a443cf2..65fd5d3ff89d 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServersManagerImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/RemoteServersManagerImpl.java @@ -3,8 +3,10 @@ package com.intellij.remoteServer.impl.configuration; import com.intellij.openapi.components.*; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.remoteServer.configuration.RemoteServerListener; import com.intellij.remoteServer.configuration.RemoteServersManager; import com.intellij.remoteServer.configuration.ServerConfiguration; +import com.intellij.util.messages.MessageBus; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializer; import org.jetbrains.annotations.NotNull; @@ -24,6 +26,11 @@ public class RemoteServersManagerImpl extends RemoteServersManager implements Pe public static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters(); private List<RemoteServer<?>> myServers = new ArrayList<RemoteServer<?>>(); private List<RemoteServerState> myUnknownServers = new ArrayList<RemoteServerState>(); + private final MessageBus myMessageBus; + + public RemoteServersManagerImpl(MessageBus messageBus) { + myMessageBus = messageBus; + } @Override public List<RemoteServer<?>> getServers() { @@ -60,11 +67,13 @@ public class RemoteServersManagerImpl extends RemoteServersManager implements Pe @Override public void addServer(RemoteServer<?> server) { myServers.add(server); + myMessageBus.syncPublisher(RemoteServerListener.TOPIC).serverAdded(server); } @Override public void removeServer(RemoteServer<?> server) { myServers.remove(server); + myMessageBus.syncPublisher(RemoteServerListener.TOPIC).serverRemoved(server); } @Nullable diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java index dc4578310663..f6ef4ddaf6d2 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java @@ -158,7 +158,6 @@ public class DeployToServerSettingsEditor<S extends ServerConfiguration, D exten return FormBuilder.createFormBuilder() .addLabeledComponent("Server:", myServerComboBox) .addLabeledComponent("Deployment:", mySourceComboBox) - .addSeparator() .addComponent(myDeploymentSettingsComponent) .getPanel(); } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionEventDispatcher.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionEventDispatcher.java new file mode 100644 index 000000000000..cd61d9522996 --- /dev/null +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionEventDispatcher.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.remoteServer.impl.runtime; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.remoteServer.runtime.ServerConnection; +import com.intellij.remoteServer.runtime.ServerConnectionListener; +import com.intellij.util.messages.MessageBus; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; + +/** + * @author nik + */ +public class ServerConnectionEventDispatcher { + private final MessageBus myMessageBus; + private final MergingUpdateQueue myEventsQueue; + + public ServerConnectionEventDispatcher() { + myMessageBus = ApplicationManager.getApplication().getMessageBus(); + myEventsQueue = new MergingUpdateQueue("remote server connection events", 500, false, null); + } + + public void fireConnectionCreated(ServerConnection<?> connection) { + myMessageBus.syncPublisher(ServerConnectionListener.TOPIC).onConnectionCreated(connection); + } + + public void queueConnectionStatusChanged(final ServerConnectionImpl<?> connection) { + myEventsQueue.activate(); + myEventsQueue.queue(new Update(connection) { + @Override + public void run() { + myMessageBus.syncPublisher(ServerConnectionListener.TOPIC).onConnectionStatusChanged(connection); + } + }); + } + + public void queueDeploymentsChanged(final ServerConnectionImpl<?> connection) { + myEventsQueue.activate(); + myEventsQueue.queue(new Update(connection) { + @Override + public void run() { + myMessageBus.syncPublisher(ServerConnectionListener.TOPIC).onDeploymentsChanged(connection); + } + }); + } +} diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java index 51548e0f90cb..d93d0c1607fd 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java @@ -3,16 +3,18 @@ package com.intellij.remoteServer.impl.runtime; import com.intellij.remoteServer.configuration.RemoteServer; import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration; import com.intellij.remoteServer.configuration.deployment.DeploymentSource; -import com.intellij.remoteServer.impl.runtime.deployment.DeploymentInformation; +import com.intellij.remoteServer.impl.runtime.deployment.DeploymentImpl; import com.intellij.remoteServer.runtime.ConnectionStatus; +import com.intellij.remoteServer.runtime.Deployment; import com.intellij.remoteServer.runtime.ServerConnection; import com.intellij.remoteServer.runtime.ServerConnector; +import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime; import com.intellij.remoteServer.runtime.deployment.DeploymentStatus; import com.intellij.remoteServer.runtime.deployment.DeploymentTask; import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.ConcurrentHashMap; +import java.util.*; /** * @author nik @@ -20,14 +22,17 @@ import java.util.concurrent.ConcurrentHashMap; public class ServerConnectionImpl<D extends DeploymentConfiguration> implements ServerConnection<D> { private final RemoteServer<?> myServer; private final ServerConnector<D> myConnector; + private final ServerConnectionEventDispatcher myEventDispatcher; private volatile ConnectionStatus myStatus = ConnectionStatus.DISCONNECTED; private volatile String myStatusText; private volatile ServerRuntimeInstance<D> myRuntimeInstance; - private final ConcurrentHashMap<DeploymentSource, DeploymentInformation> myDeploymentInfos = new ConcurrentHashMap<DeploymentSource, DeploymentInformation>(); + private final Map<String, Deployment> myRemoteDeployments = new HashMap<String, Deployment>(); + private final Map<DeploymentSource, Deployment> myLocalDeployments = Collections.synchronizedMap(new HashMap<DeploymentSource, Deployment>()); - public ServerConnectionImpl(RemoteServer<?> server, ServerConnector<D> connector) { + public ServerConnectionImpl(RemoteServer<?> server, ServerConnector<D> connector, ServerConnectionEventDispatcher eventDispatcher) { myServer = server; myConnector = connector; + myEventDispatcher = eventDispatcher; } @NotNull @@ -45,7 +50,7 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements @NotNull @Override public String getStatusText() { - return myStatusText; + return myStatusText != null ? myStatusText : myStatus.getPresentableText(); } @Override @@ -68,7 +73,7 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements if (myStatus == ConnectionStatus.CONNECTED) { myRuntimeInstance = null; myConnector.disconnect(); - myStatus = ConnectionStatus.DISCONNECTED; + setStatus(ConnectionStatus.DISCONNECTED); } } @@ -77,30 +82,59 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements connectIfNeeded(new ConnectionCallbackBase<D>() { @Override public void connected(@NotNull ServerRuntimeInstance<D> instance) { - myDeploymentInfos.put(task.getSource(), new DeploymentInformation(DeploymentStatus.DEPLOYING)); - instance.deploy(task, new UpdateDeploymentStatusCallback(task.getSource(), DeploymentStatus.DEPLOYED, - DeploymentStatus.NOT_DEPLOYED)); + DeploymentSource source = task.getSource(); + String deploymentName = instance.getDeploymentName(source); + myLocalDeployments.put(source, new DeploymentImpl(deploymentName, DeploymentStatus.DEPLOYING, null, null)); + instance.deploy(task, new DeploymentOperationCallbackImpl(task.getSource(), deploymentName)); } }); } @Override - public void undeploy(@NotNull final DeploymentTask<D> task) { + public void computeDeployments(@NotNull final Runnable onFinished) { connectIfNeeded(new ConnectionCallbackBase<D>() { @Override public void connected(@NotNull ServerRuntimeInstance<D> instance) { - myDeploymentInfos.put(task.getSource(), new DeploymentInformation(DeploymentStatus.UNDEPLOYING)); - instance.undeploy(task, new UpdateDeploymentStatusCallback(task.getSource(), DeploymentStatus.NOT_DEPLOYED, - DeploymentStatus.DEPLOYED)); + instance.computeDeployments(new ServerRuntimeInstance.ComputeDeploymentsCallback() { + @Override + public void succeeded(@NotNull List<Deployment> deployments) { + synchronized (myRemoteDeployments) { + myRemoteDeployments.clear(); + for (Deployment deployment : deployments) { + myRemoteDeployments.put(deployment.getName(), deployment); + } + } + myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this); + onFinished.run(); + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + synchronized (myRemoteDeployments) { + myRemoteDeployments.clear(); + } + myStatusText = "Cannot obtain deployments: " + errorMessage; + myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this); + onFinished.run(); + } + }); } }); } @NotNull @Override - public DeploymentStatus getDeploymentStatus(@NotNull DeploymentSource source) { - DeploymentInformation information = myDeploymentInfos.get(source); - return information != null ? information.getStatus() : DeploymentStatus.NOT_DEPLOYED; + public Collection<Deployment> getDeployments() { + Map<String, Deployment> result; + synchronized (myRemoteDeployments) { + result = new HashMap<String, Deployment>(myRemoteDeployments); + } + synchronized (myLocalDeployments) { + for (Deployment deployment : myLocalDeployments.values()) { + result.put(deployment.getName(), deployment); + } + } + return result.values(); } private void connectIfNeeded(final ServerConnector.ConnectionCallback<D> callback) { @@ -110,18 +144,18 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements return; } - myStatus = ConnectionStatus.CONNECTING; + setStatus(ConnectionStatus.CONNECTING); myConnector.connect(new ServerConnector.ConnectionCallback<D>() { @Override public void connected(@NotNull ServerRuntimeInstance<D> instance) { - myStatus = ConnectionStatus.CONNECTED; + setStatus(ConnectionStatus.CONNECTED); myRuntimeInstance = instance; callback.connected(instance); } @Override public void errorOccurred(@NotNull String errorMessage) { - myStatus = ConnectionStatus.DISCONNECTED; + setStatus(ConnectionStatus.DISCONNECTED); myRuntimeInstance = null; myStatusText = errorMessage; callback.errorOccurred(errorMessage); @@ -129,31 +163,36 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements }); } + private void setStatus(final ConnectionStatus status) { + myStatus = status; + myEventDispatcher.queueConnectionStatusChanged(this); + } + private static abstract class ConnectionCallbackBase<D extends DeploymentConfiguration> implements ServerConnector.ConnectionCallback<D> { @Override public void errorOccurred(@NotNull String errorMessage) { } } - private class UpdateDeploymentStatusCallback implements ServerRuntimeInstance.DeploymentOperationCallback { + private class DeploymentOperationCallbackImpl implements ServerRuntimeInstance.DeploymentOperationCallback { private final DeploymentSource mySource; - private DeploymentStatus mySuccessStatus; - private DeploymentStatus myFailedStatus; + private final String myDeploymentName; - public UpdateDeploymentStatusCallback(DeploymentSource source, final DeploymentStatus successStatus, final DeploymentStatus failedStatus) { + public DeploymentOperationCallbackImpl(DeploymentSource source, String deploymentName) { mySource = source; - mySuccessStatus = successStatus; - myFailedStatus = failedStatus; + myDeploymentName = deploymentName; } @Override - public void succeeded() { - myDeploymentInfos.put(mySource, new DeploymentInformation(mySuccessStatus)); + public void succeeded(@NotNull DeploymentRuntime deployment) { + myLocalDeployments.put(mySource, new DeploymentImpl(myDeploymentName, DeploymentStatus.DEPLOYED, null, deployment)); + myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this); } @Override public void errorOccurred(@NotNull String errorMessage) { - myDeploymentInfos.put(mySource, new DeploymentInformation(myFailedStatus, errorMessage)); + myLocalDeployments.put(mySource, new DeploymentImpl(myDeploymentName, DeploymentStatus.NOT_DEPLOYED, errorMessage, null)); + myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this); } } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionManagerImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionManagerImpl.java index 66a56da6ddd5..af9d1412f802 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionManagerImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionManagerImpl.java @@ -6,6 +6,7 @@ import com.intellij.remoteServer.configuration.ServerConfiguration; import com.intellij.remoteServer.runtime.ServerConnection; import com.intellij.remoteServer.runtime.ServerConnectionManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; @@ -17,6 +18,7 @@ import java.util.Map; */ public class ServerConnectionManagerImpl extends ServerConnectionManager { private Map<RemoteServer<?>, ServerConnection> myConnections = new HashMap<RemoteServer<?>, ServerConnection>(); + private final ServerConnectionEventDispatcher myEventDispatcher = new ServerConnectionEventDispatcher(); @NotNull @Override @@ -25,12 +27,19 @@ public class ServerConnectionManagerImpl extends ServerConnectionManager { ServerConnection connection = myConnections.get(server); if (connection == null) { ServerTaskExecutorImpl executor = new ServerTaskExecutorImpl(); - connection = new ServerConnectionImpl(server, server.getType().createConnector(server.getConfiguration(), executor)); + connection = new ServerConnectionImpl(server, server.getType().createConnector(server.getConfiguration(), executor), myEventDispatcher); myConnections.put(server, connection); + myEventDispatcher.fireConnectionCreated(connection); } return connection; } + @Nullable + @Override + public <C extends ServerConfiguration> ServerConnection getConnection(@NotNull RemoteServer<C> server) { + return myConnections.get(server); + } + @NotNull @Override public Collection<ServerConnection> getConnections() { diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java new file mode 100644 index 000000000000..9d4154560f66 --- /dev/null +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java @@ -0,0 +1,44 @@ +package com.intellij.remoteServer.impl.runtime.deployment; + +import com.intellij.remoteServer.runtime.Deployment; +import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime; +import com.intellij.remoteServer.runtime.deployment.DeploymentStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public class DeploymentImpl implements Deployment { + private final String myName; + private final DeploymentStatus myStatus; + private final String myStatusText; + private final DeploymentRuntime myRuntime; + + public DeploymentImpl(@NotNull String name, @NotNull DeploymentStatus status, @Nullable String statusText, @Nullable DeploymentRuntime runtime) { + myName = name; + myStatus = status; + myStatusText = statusText; + myRuntime = runtime; + } + + @NotNull + public String getName() { + return myName; + } + + @Override + @NotNull + public DeploymentStatus getStatus() { + return myStatus; + } + + @NotNull + public String getStatusText() { + return myStatusText != null ? myStatusText : myStatus.getPresentableText(); + } + + public DeploymentRuntime getRuntime() { + return myRuntime; + } +} diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index 1b975ee070b3..721c6d1afb4e 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -40,7 +40,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP private final TIntObjectHashMap<Node> myNodeByIdMap = new TIntObjectHashMap<Node>(); private final Set<Node> myRunningNodes = ContainerUtil.newHashSet(); - private final List<SMTRunnerEventsListener> myEventsListeners = ContainerUtil.createEmptyCOWList(); + private final List<SMTRunnerEventsListener> myEventsListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final SMTestProxy.SMRootTestProxy myTestsRootProxy; private final Node myTestsRootNode; private final String myTestFrameworkName; diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java index c30f85a058b2..7aea8e9b6cc1 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java @@ -38,16 +38,13 @@ public class SMTRunnerConsoleView extends BaseTestsOutputConsoleView { private final ExecutionEnvironment myEnvironment; private SMTestRunnerResultsForm myResultsViewer; @Nullable private final String mySplitterProperty; - private final List<AttachToProcessListener> myAttachToProcessListeners = ContainerUtil.createEmptyCOWList(); + private final List<AttachToProcessListener> myAttachToProcessListeners = ContainerUtil.createLockFreeCopyOnWriteList(); public SMTRunnerConsoleView(final TestConsoleProperties consoleProperties, final ExecutionEnvironment environment) { this(consoleProperties, environment, null); } /** - * @param consoleProperties - * @param runnerSettings - * @param configurationPerRunnerSettings * @param splitterProperty Key to store(project level) latest value of testTree/consoleTab splitter. E.g. "RSpec.Splitter.Proportion" */ public SMTRunnerConsoleView(final TestConsoleProperties consoleProperties, diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 31c7afcb8a93..32abf992a046 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -49,6 +49,8 @@ import com.intellij.ide.startup.StartupManagerEx; import com.intellij.ide.startup.impl.StartupManagerImpl; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.newStructureView.StructureViewComponent; +import com.intellij.injected.editor.DocumentWindow; +import com.intellij.injected.editor.EditorWindow; import com.intellij.internal.DumpLookupElementWeights; import com.intellij.lang.LanguageStructureViewBuilder; import com.intellij.openapi.Disposable; @@ -81,10 +83,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.openapi.vfs.*; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; @@ -348,7 +347,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig for (String path : filePaths) { files.add(copyFileToProject(path)); } - return testHighlightingAllFiles(checkWarnings, checkInfos, checkWeakWarnings, VfsUtil.toVirtualFileArray(files)); + return testHighlightingAllFiles(checkWarnings, checkInfos, checkWeakWarnings, VfsUtilCore.toVirtualFileArray(files)); } @Override @@ -525,7 +524,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @NotNull public List<IntentionAction> getAvailableIntentions() { doHighlighting(); - return getAvailableIntentions(myEditor, myFile); + PsiFile file = getFile(); + Editor editor = getEditor(); + if (editor instanceof EditorWindow) { + editor = ((EditorWindow)editor).getDelegate(); + file = InjectedLanguageUtil.getTopLevelFile(file); + } + return getAvailableIntentions(editor, file); } @Override @@ -1034,7 +1039,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig protected void run(Result result) throws Throwable { PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); EditorUtil.fillVirtualSpaceUntilCaret(myEditor); - checkResult("TEXT", stripTrailingSpaces, SelectionAndCaretMarkupLoader.fromText(text, getProject()), myFile.getText()); + checkResult("TEXT", stripTrailingSpaces, SelectionAndCaretMarkupLoader.fromText(text, getProject()), getHostFile().getText()); } }.execute(); } @@ -1051,7 +1056,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @Override protected void run() throws Exception { - checkResultByFile(expectedFile, myFile, ignoreTrailingWhitespaces); + checkResultByFile(expectedFile, getHostFile(), ignoreTrailingWhitespaces); } }.execute().throwException(); } @@ -1358,6 +1363,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig module.getMessageBus().syncPublisher(FacetManager.FACETS_TOPIC).facetConfigurationChanged(facet); } } + setupEditorForInjectedLanguage(); } }.execute().throwException(); @@ -1365,6 +1371,15 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig return myFile; } + private void setupEditorForInjectedLanguage() { + Editor editor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(myEditor, myFile); + if (editor instanceof EditorWindow) { + myFile = ((EditorWindow)editor).getInjectedFile(); + myEditor = editor; + } + } + + @Override public VirtualFile findFileInTempDir(final String filePath) { if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) { @@ -1390,16 +1405,21 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig private long collectAndCheckHighlightings(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) throws Exception { ExpectedHighlightingData data = - new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, myFile); + new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, getHostFile()); data.init(); return collectAndCheckHighlightings(data); } - private long collectAndCheckHighlightings(final ExpectedHighlightingData data) { + private PsiFile getHostFile() { + return InjectedLanguageUtil.getTopLevelFile(myFile); + } + + private long collectAndCheckHighlightings(@NotNull ExpectedHighlightingData data) { final Project project = getProject(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - FileElement hardRefToFileElement = ((PsiFileImpl)myFile).calcTreeElement();//to load text + PsiFileImpl file = (PsiFileImpl)getHostFile(); + FileElement hardRefToFileElement = file.calcTreeElement();//to load text //to initialize caches if (!DumbService.isDumb(project)) { @@ -1421,7 +1441,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } final long elapsed = System.currentTimeMillis() - start; - data.checkResult(infos, myEditor.getDocument().getText()); + data.checkResult(infos, file.getText()); hardRefToFileElement.hashCode(); // use it so gc won't collect it return elapsed; } @@ -1454,7 +1474,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig final Project project = getProject(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - return instantiateAndRun(getFile(), getEditor(), ArrayUtil.EMPTY_INT_ARRAY, myAllowDirt); + PsiFile file = getFile(); + Editor editor = getEditor(); + if (editor instanceof EditorWindow) { + editor = ((EditorWindow)editor).getDelegate(); + file = InjectedLanguageUtil.getTopLevelFile(file); + } + return instantiateAndRun(file, editor, ArrayUtil.EMPTY_INT_ARRAY, myAllowDirt); } @NotNull @@ -1580,7 +1606,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig static SelectionAndCaretMarkupLoader fromFile(VirtualFile file, Project project) { final String text; try { - text = VfsUtil.loadText(file); + text = VfsUtilCore.loadText(file); } catch (IOException e) { throw new RuntimeException(e); @@ -1661,6 +1687,12 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig String actualText) { assertInitialized(); Project project = getProject(); + PsiFile file = getFile(); + Editor editor = getEditor(); + if (editor instanceof EditorWindow) { + editor = ((EditorWindow)editor).getDelegate(); + file = InjectedLanguageUtil.getTopLevelFile(file); + } project.getComponent(PostprocessReformattingAspect.class).doPostponedFormatting(); if (stripTrailingSpaces) { @@ -1689,10 +1721,11 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig final int tabSize = CodeStyleSettingsManager.getSettings(getProject()).getIndentOptions(StdFileTypes.JAVA).TAB_SIZE; int caretLine = StringUtil.offsetToLineNumber(loader.newFileText, loader.caretMarker.getStartOffset()); - int caretCol = EditorUtil.calcColumnNumber(null, loader.newFileText, StringUtil.lineColToOffset(loader.newFileText, caretLine, 0), loader.caretMarker.getStartOffset(), tabSize); + int caretCol = EditorUtil.calcColumnNumber(null, loader.newFileText, StringUtil.lineColToOffset(loader.newFileText, caretLine, 0), + loader.caretMarker.getStartOffset(), tabSize); - final int actualLine = myEditor.getCaretModel().getLogicalPosition().line; - final int actualCol = myEditor.getCaretModel().getLogicalPosition().column; + final int actualLine = editor.getCaretModel().getLogicalPosition().line; + final int actualCol = editor.getCaretModel().getLogicalPosition().column; boolean caretPositionEquals = caretLine == actualLine && caretCol == actualCol; Assert.assertTrue("Caret position in " + expectedFile + " differs. Expected " + genCaretPositionPresentation(caretLine, caretCol) + ". Actual " + genCaretPositionPresentation(actualLine, actualCol), caretPositionEquals); @@ -1707,15 +1740,15 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig int selectionStart; int selectionEnd; - if (myEditor.getSelectionModel().hasBlockSelection()) { - int[] starts = myEditor.getSelectionModel().getBlockSelectionStarts(); - int[] ends = myEditor.getSelectionModel().getBlockSelectionEnds(); + if (editor.getSelectionModel().hasBlockSelection()) { + int[] starts = editor.getSelectionModel().getBlockSelectionStarts(); + int[] ends = editor.getSelectionModel().getBlockSelectionEnds(); selectionStart = starts[starts.length-1]; selectionEnd = ends[ends.length-1]; } else { - selectionStart = myEditor.getSelectionModel().getSelectionStart(); - selectionEnd = myEditor.getSelectionModel().getSelectionEnd(); + selectionStart = editor.getSelectionModel().getSelectionStart(); + selectionEnd = editor.getSelectionModel().getSelectionEnd(); } final int selStartLineActual = StringUtil.offsetToLineNumber(loader.newFileText, selectionStart); @@ -1733,8 +1766,8 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig ". Actual " + genSelectionPresentation(selStartLineActual, selStartColActual, selEndLineActual, selEndColActual), selectionEquals); } - else if (myEditor != null) { - Assert.assertTrue("has no selection in " + expectedFile, !myEditor.getSelectionModel().hasSelection()); + else if (editor != null) { + Assert.assertTrue("has no selection in " + expectedFile, !editor.getSelectionModel().hasSelection()); } } @@ -1900,4 +1933,12 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig return (LookupImpl)LookupManager.getActiveLookup(myEditor); } + protected void bringRealEditorBack() { + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + if (myEditor instanceof EditorWindow) { + Document document = ((DocumentWindow)myEditor.getDocument()).getDelegate(); + myFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document); + myEditor = ((EditorWindow)myEditor).getDelegate(); + } + } } diff --git a/platform/usageView/src/com/intellij/usages/UsageTargetUtil.java b/platform/usageView/src/com/intellij/usages/UsageTargetUtil.java index 7050dbbceca0..9e841dfa53c5 100644 --- a/platform/usageView/src/com/intellij/usages/UsageTargetUtil.java +++ b/platform/usageView/src/com/intellij/usages/UsageTargetUtil.java @@ -21,10 +21,13 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -60,7 +63,9 @@ public class UsageTargetUtil { public static UsageTarget[] findUsageTargets(PsiElement psiElement) { List<UsageTarget> result = new ArrayList<UsageTarget>(); - for (UsageTargetProvider provider : Extensions.getExtensions(EP_NAME)) { + UsageTargetProvider[] providers = Extensions.getExtensions(EP_NAME); + Project project = psiElement.getProject(); + for (UsageTargetProvider provider : DumbService.getInstance(project).filterByDumbAwareness(Arrays.asList(providers))) { UsageTarget[] targets = provider.getTargets(psiElement); if (targets != null) Collections.addAll(result, targets); } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 9b6cbe620a26..bf98ac24d66a 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -1434,6 +1434,10 @@ public class ContainerUtil extends ContainerUtilRt { */ @NotNull public static <T, V> List<V> mapNotNull(@NotNull Collection<? extends T> iterable, @NotNull Function<T, V> mapping) { + if (iterable.isEmpty()) { + return emptyList(); + } + List<V> result = new ArrayList<V>(iterable.size()); for (T t : iterable) { final V o = mapping.fun(t); diff --git a/platform/util/src/com/intellij/util/io/IOUtil.java b/platform/util/src/com/intellij/util/io/IOUtil.java index 2222f8ccaf96..0985466d5965 100644 --- a/platform/util/src/com/intellij/util/io/IOUtil.java +++ b/platform/util/src/com/intellij/util/io/IOUtil.java @@ -121,6 +121,7 @@ public class IOUtil { return result; } + if (len == 0) return ""; storage.readFully(buffer, 0, len); return new String(buffer, 0, len, US_ASCII); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/RequestsMerger.java b/platform/vcs-api/src/com/intellij/openapi/vcs/RequestsMerger.java index 49038a5cae2b..6f27bf76c693 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/RequestsMerger.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/RequestsMerger.java @@ -31,16 +31,14 @@ import java.util.Map; /** * For exactly same refresh requests buffering: - * - * - refresh requests can be merged into one, but general principle is that each request should be reliably followed by refresh action + * <p/> + * - refresh requests can be merged into one, but general principle is that each request should be reliably followed by refresh action * - at the moment only one refresh action is being done * - if request had been submitted while refresh action was in progress, new refresh action is initiated right after first refresh action finishes - * */ @SomeQueue public class RequestsMerger { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.RequestsMerger"); - private static final int ourDelay = 300; private final MyWorker myWorker; @@ -48,18 +46,15 @@ public class RequestsMerger { private MyState myState; private final Consumer<Runnable> myAlarm; - - private final List<Runnable> myWaitingStartListeners; - private final List<Runnable> myWaitingFinishListeners; + + private final List<Runnable> myWaitingStartListeners = new ArrayList<Runnable>(); + private final List<Runnable> myWaitingFinishListeners = new ArrayList<Runnable>(); public RequestsMerger(final Runnable runnable, final Consumer<Runnable> alarm) { myAlarm = alarm; myWorker = new MyWorker(runnable); myState = MyState.empty; - - myWaitingStartListeners = new ArrayList<Runnable>(); - myWaitingFinishListeners = new ArrayList<Runnable>(); } public void request() { @@ -75,35 +70,23 @@ public class RequestsMerger { request(); } - public void ensureInitialization(final Runnable runnable) { - LOG.debug("ext: ensure init"); - synchronized (myLock) { - if (myWorker.isInitialized()) { - runnable.run(); - return; - } - myWaitingStartListeners.add(runnable); - } - request(); - } - private class MyWorker implements Runnable { - private boolean myInitialized; + private volatile boolean myInitialized; private final Runnable myRunnable; private MyWorker(Runnable runnable) { myRunnable = runnable; } + @Override public void run() { LOG.debug("worker: started refresh"); try { doAction(MyAction.start); myRunnable.run(); - synchronized (myLock) { - myInitialized = true; - } - } finally { + myInitialized = true; + } + finally { doAction(MyAction.finish); } } @@ -125,8 +108,9 @@ public class RequestsMerger { LOG.debug("doAction: oldState: " + oldState.name() + ", newState: " + myState.name()); - if (LOG.isDebugEnabled() && (exitActions != null)) { + if (LOG.isDebugEnabled() && exitActions != null) { final String debugExitActions = StringUtil.join(exitActions, new Function<MyExitAction, String>() { + @Override public String fun(MyExitAction exitAction) { return exitAction.name(); } @@ -138,7 +122,8 @@ public class RequestsMerger { if (MyExitAction.markStart.equals(exitAction)) { myWaitingFinishListeners.addAll(myWaitingStartListeners); myWaitingStartListeners.clear(); - } else if (MyExitAction.markEnd.equals(exitAction)) { + } + else if (MyExitAction.markEnd.equals(exitAction)) { toBeCalled = new ArrayList<Runnable>(myWaitingFinishListeners); myWaitingFinishListeners.clear(); } @@ -164,6 +149,7 @@ public class RequestsMerger { private static enum MyState { empty() { + @Override @NotNull public MyState transition(MyAction action) { if (MyAction.request.equals(action)) { @@ -171,19 +157,24 @@ public class RequestsMerger { } logWrongAction(this, action); return this; - }}, + } + }, inProgress() { + @Override @NotNull public MyState transition(MyAction action) { if (MyAction.finish.equals(action)) { - return MyState.empty; - } else if (MyAction.request.equals(action)) { + return empty; + } + else if (MyAction.request.equals(action)) { return MyState.inProgressRequestSubmitted; } logWrongAction(this, action); return this; - }}, + } + }, inProgressRequestSubmitted() { + @Override @NotNull public MyState transition(MyAction action) { if (MyAction.finish.equals(action)) { @@ -193,19 +184,23 @@ public class RequestsMerger { logWrongAction(this, action); } return this; - }}, + } + }, requestSubmitted() { + @Override @NotNull public MyState transition(MyAction action) { if (MyAction.start.equals(action)) { - return MyState.inProgress; - } else if (MyAction.finish.equals(action)) { + return inProgress; + } + else if (MyAction.finish.equals(action)) { // to be able to be started by another request logWrongAction(this, action); - return MyState.empty; + return empty; } return this; - }}; + } + }; // under lock @NotNull @@ -217,7 +212,7 @@ public class RequestsMerger { } private static class MyTransitionAction { - private final static Map<Pair<MyState, MyState>, MyExitAction[]> myMap = new HashMap<Pair<MyState, MyState>, MyExitAction[]>(); + private static final Map<Pair<MyState, MyState>, MyExitAction[]> myMap = new HashMap<Pair<MyState, MyState>, MyExitAction[]>(); static { add(MyState.empty, MyState.requestSubmitted, MyExitAction.submitRequestToExecutor); @@ -230,7 +225,7 @@ public class RequestsMerger { add(MyState.inProgress, MyState.requestSubmitted, MyExitAction.markEnd); } - private static void add(final MyState from , final MyState to, final MyExitAction... action) { + private static void add(final MyState from, final MyState to, final MyExitAction... action) { myMap.put(new Pair<MyState, MyState>(from, to), action); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java index f5e2de674959..35b3a2adcbcf 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java @@ -152,9 +152,6 @@ public final class VcsConfiguration implements PersistentStateComponent<VcsConfi private final PerformInBackgroundOption myCheckoutOption = new CheckoutInBackgroundOption(); private final PerformInBackgroundOption myAddRemoveOption = new AddRemoveInBackgroundOption(); - public VcsConfiguration() { - } - public VcsConfiguration getState() { return this; } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsShowConfirmationOption.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsShowConfirmationOption.java index 9322251a1871..5f5c75e94f82 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsShowConfirmationOption.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsShowConfirmationOption.java @@ -15,6 +15,8 @@ */ package com.intellij.openapi.vcs; +import org.jetbrains.annotations.NotNull; + public interface VcsShowConfirmationOption { enum Value { @@ -29,7 +31,7 @@ public interface VcsShowConfirmationOption { } @Deprecated - public static Value fromString(String s){ + public static Value fromString(@NotNull String s){ if (s.equals("1")) return DO_NOTHING_SILENTLY; if (s.equals("2")) return DO_ACTION_SILENTLY; return SHOW_CONFIRMATION; diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java index 78bf3fcb7c6e..48fdb829460f 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java @@ -74,7 +74,7 @@ public abstract class XLineBreakpointType<P extends XBreakpointProperties> exten return fileLineDisplayText(breakpoint.getPresentableFilePath(), breakpoint.getLine()); } - private String fileLineDisplayText(String path, int line) { + private static String fileLineDisplayText(String path, int line) { return XDebuggerBundle.message("xbreakpoint.default.display.text", line + 1, path); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index e493c05ef611..9353bfb55eb5 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -32,6 +32,7 @@ import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.notification.Notification; import com.intellij.notification.NotificationGroup; import com.intellij.notification.NotificationListener; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; @@ -43,6 +44,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.ui.AppUIUtil; import com.intellij.util.EventDispatcher; +import com.intellij.util.SmartList; import com.intellij.util.ui.UIUtil; import com.intellij.xdebugger.*; import com.intellij.xdebugger.breakpoints.*; @@ -73,7 +75,8 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class XDebugSessionImpl implements XDebugSession { private static final Logger LOG = Logger.getInstance("#com.intellij.xdebugger.impl.XDebugSessionImpl"); - public static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Debugger messages", ToolWindowId.DEBUG, false); + public static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Debugger messages", ToolWindowId.DEBUG, + false); private XDebugProcess myDebugProcess; private final Map<XBreakpoint<?>, CustomizedBreakpointPresentation> myRegisteredBreakpoints = new HashMap<XBreakpoint<?>, CustomizedBreakpointPresentation>(); @@ -100,6 +103,7 @@ public class XDebugSessionImpl implements XDebugSession { private boolean myStopped; private boolean myPauseActionSupported; private boolean myShowTabOnSuspend; + private final List<AnAction> myRestartActions = new SmartList<AnAction>(); private ConsoleView myConsoleView; private final Icon myIcon; @@ -155,6 +159,14 @@ public class XDebugSessionImpl implements XDebugSession { public void setAutoInitBreakpoints(boolean value) { autoInitBreakpoints = value; } + + public List<AnAction> getRestartActions() { + return myRestartActions; + } + + public void addRestartActions(AnAction... restartActions) { + Collections.addAll(myRestartActions, restartActions); + } @Override public void rebuildViews() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java index ba91f761ab15..7bcc401fb759 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,8 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XDebuggerUtil; -import com.intellij.xdebugger.breakpoints.XBreakpointProperties; -/** -* @author nik -*/ -class RemoveBreakpointGutterIconAction<P extends XBreakpointProperties> extends AnAction { +class RemoveBreakpointGutterIconAction extends AnAction { private XBreakpointBase<?,?,?> myBreakpoint; RemoveBreakpointGutterIconAction(XBreakpointBase<?, ?, ?> breakpoint) { @@ -35,4 +31,4 @@ class RemoveBreakpointGutterIconAction<P extends XBreakpointProperties> extends public void actionPerformed(final AnActionEvent e) { XDebuggerUtil.getInstance().removeBreakpoint(myBreakpoint.getProject(), myBreakpoint); } -} +}
\ No newline at end of file diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java index 044682be27be..fe2bfea10f00 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java @@ -345,7 +345,7 @@ public class XBreakpointBase<Self extends XBreakpoint<P>, P extends XBreakpointP } @Override - public int compareTo(Self self) { + public int compareTo(@NotNull Self self) { return myType.getBreakpointComparator().compare((Self)this, self); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index ff280e675683..d7a5468ebd66 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -130,7 +130,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { return myWatchesView; } - private void attachToSession(final @NotNull XDebugSession session, final @Nullable ProgramRunner runner, + private void attachToSession(final @NotNull XDebugSessionImpl session, final @Nullable ProgramRunner runner, final @Nullable ExecutionEnvironment env, final @NotNull XDebugSessionData sessionData, final @NotNull XDebugProcess debugProcess) { myUi.addContent(createFramesContent(session), 0, PlaceInGrid.left, false); @@ -163,6 +163,10 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { RestartAction restartAction = new RestartAction(executor, runner, myRunContentDescriptor, env); leftToolbar.add(restartAction); restartAction.registerShortcut(myUi.getComponent()); + + List<AnAction> additionalRestartActions = session.getRestartActions(); + leftToolbar.addAll(additionalRestartActions); + if (!additionalRestartActions.isEmpty()) leftToolbar.addSeparator(); } leftToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_LEFT_TOOLBAR_GROUP)); diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java index 5e0b960ed269..fc0d1102326e 100644 --- a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java +++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java @@ -22,7 +22,6 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.ListWithSelection; -import com.intellij.util.ui.ComboBoxTableCellEditor; import com.intellij.util.ui.ComboBoxTableCellRenderer; import git4idea.GitUtil; import git4idea.config.GitConfigUtil; @@ -105,6 +104,7 @@ public class GitRebaseEditor extends DialogWrapper { myGitRoot = gitRoot; setTitle(GitBundle.getString("rebase.editor.title")); setOKButtonText(GitBundle.getString("rebase.editor.button")); + if (SystemInfo.isWindows && file.startsWith(CYGDRIVE_PREFIX)) { final int prefixSize = CYGDRIVE_PREFIX.length(); file = file.substring(prefixSize, prefixSize + 1) + ":" + file.substring(prefixSize + 1); @@ -114,9 +114,15 @@ public class GitRebaseEditor extends DialogWrapper { myTableModel.load(file); myCommitsTable.setModel(myTableModel); myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + + final JComboBox editorComboBox = new JComboBox(); + for (Object option : GitRebaseEntry.Action.values()) { + editorComboBox.addItem(option); + } TableColumn actionColumn = myCommitsTable.getColumnModel().getColumn(MyTableModel.ACTION); - actionColumn.setCellEditor(ComboBoxTableCellEditor.INSTANCE); + actionColumn.setCellEditor(new DefaultCellEditor(editorComboBox)); actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE); + myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(final ListSelectionEvent e) { myViewButton.setEnabled(myCommitsTable.getSelectedRowCount() == 1); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java index f6c075f0fda6..0ca65ea8a666 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java @@ -100,7 +100,7 @@ public class GithubCreateGistAction extends DumbAwareAction { @Nullable final VirtualFile[] files) { // Ask for description and other params - final GithubCreateGistDialog dialog = new GithubCreateGistDialog(project, editor, file); + final GithubCreateGistDialog dialog = new GithubCreateGistDialog(project, editor, files, file); dialog.show(); if (!dialog.isOK()) { return; diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 60e6bb91ea4d..472be8864dd7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -30,8 +30,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; -import javax.swing.SwingWorker; - import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.ContainerUtil; import git4idea.DialogManager; @@ -71,7 +69,7 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { return; } - if (StringUtil.isEmptyOrSpaces(GithubSettings.getInstance().getLogin())) { + if (!GithubSettings.getInstance().isAuthConfigured()) { setVisibleEnabled(e, false, false); return; } @@ -134,13 +132,13 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { return; } - final GithubInfo info = loadGithubInfoWithModal(project, userAndRepo); + final GithubInfo info = loadGithubInfoWithModal(project, userAndRepo, upstreamUserAndRepo); if (info == null) { return; } - final GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(project); - initLoadAvailableBranches(project, info, upstreamUserAndRepo, dialog); + String suggestedBranch = info.getRepo().getParent() == null ? null : info.getRepo().getParent().getUserName() + ":master"; + final GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(project, info.getBranches(), suggestedBranch); DialogManager.show(dialog); if (!dialog.isOK()) { return; @@ -171,7 +169,9 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } @Nullable - private static GithubInfo loadGithubInfoWithModal(@NotNull final Project project, @NotNull final GithubFullPath userAndRepo) { + private static GithubInfo loadGithubInfoWithModal(@NotNull final Project project, + @NotNull final GithubFullPath userAndRepo, + @Nullable final GithubFullPath upstreamUserAndRepo) { final Ref<GithubInfo> githubInfoRef = new Ref<GithubInfo>(); final Ref<IOException> exceptionRef = new Ref<IOException>(); ProgressManager.getInstance().run(new Task.Modal(project, "Access to GitHub", true) { @@ -185,7 +185,8 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { reposRef.set(GithubApiUtil.getDetailedRepoInfo(authData, userAndRepo.getUser(), userAndRepo.getRepository())); } }); - githubInfoRef.set(new GithubInfo(auth, reposRef.get())); + List<String> branches = loadAvailableBranches(project, auth, reposRef.get(), upstreamUserAndRepo); + githubInfoRef.set(new GithubInfo(auth, reposRef.get(), branches)); } catch (IOException e) { exceptionRef.set(e); @@ -280,85 +281,70 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { return StringUtil.equalsIgnoreCase(user, repo.getUserName()); } - private static void initLoadAvailableBranches(@NotNull final Project project, - @NotNull final GithubInfo info, - @Nullable final GithubFullPath upstreamPath, - @NotNull final GithubCreatePullRequestDialog dialog) { - dialog.setBusy(true); - new SwingWorker<List<String>, Void>() { - @Override - protected List<String> doInBackground() throws Exception { - List<String> result = new ArrayList<String>(); - try { - final GithubAuthData auth = info.getAuthData(); - final GithubRepoDetailed repo = info.getRepo(); - final GithubRepo parent = repo.getParent(); - final GithubRepo source = repo.getSource(); - - result.addAll(getBranches(auth, repo.getUserName(), repo.getName())); + private static List<String> loadAvailableBranches(@NotNull final Project project, + @NotNull final GithubAuthData auth, + @NotNull final GithubRepoDetailed repo, + @Nullable final GithubFullPath upstreamPath) { + List<String> result = new ArrayList<String>(); + try { + final GithubRepo parent = repo.getParent(); + final GithubRepo source = repo.getSource(); - if (parent != null) { - result.addAll(getBranches(auth, parent.getUserName(), parent.getName())); - } + if (parent != null) { + result.addAll(getBranches(auth, parent.getUserName(), parent.getName())); + } - if (source != null && !equals(source, parent)) { - result.addAll(getBranches(auth, source.getUserName(), source.getName())); - } + result.addAll(getBranches(auth, repo.getUserName(), repo.getName())); - if (upstreamPath != null && !equals(upstreamPath, repo) && !equals(upstreamPath, parent) && !equals(upstreamPath, source)) { - result.addAll(getBranches(auth, upstreamPath.getUser(), upstreamPath.getRepository())); - } - } - catch (IOException e) { - GithubNotifications.showError(project, "Can't load available branches", e); - } - return result; + if (source != null && !equals(source, parent)) { + result.addAll(getBranches(auth, source.getUserName(), source.getName())); } - @Override - protected void done() { - try { - dialog.addBranches(get()); - } - catch (Exception ignore) { - } - dialog.setBusy(false); + if (upstreamPath != null && !equals(upstreamPath, repo) && !equals(upstreamPath, parent) && !equals(upstreamPath, source)) { + result.addAll(getBranches(auth, upstreamPath.getUser(), upstreamPath.getRepository())); } + } + catch (IOException e) { + GithubNotifications.showError(project, "Can't load available branches", e); + } + return result; + } - @NotNull - private List<String> getBranches(@NotNull GithubAuthData auth, @NotNull final String user, @NotNull String repo) throws IOException { - List<GithubBranch> branches = GithubApiUtil.getRepoBranches(auth, user, repo); - return ContainerUtil.map(branches, new Function<GithubBranch, String>() { - @Override - public String fun(GithubBranch branch) { - return user + ":" + branch.getName(); - } - }); + @NotNull + private static List<String> getBranches(@NotNull GithubAuthData auth, @NotNull final String user, @NotNull String repo) + throws IOException { + List<GithubBranch> branches = GithubApiUtil.getRepoBranches(auth, user, repo); + return ContainerUtil.map(branches, new Function<GithubBranch, String>() { + @Override + public String fun(GithubBranch branch) { + return user + ":" + branch.getName(); } + }); + } - private boolean equals(@NotNull GithubRepo repo1, @Nullable GithubRepo repo2) { - if (repo2 == null) { - return false; - } - return StringUtil.equalsIgnoreCase(repo1.getUserName(), repo2.getUserName()); - } + private static boolean equals(@NotNull GithubRepo repo1, @Nullable GithubRepo repo2) { + if (repo2 == null) { + return false; + } + return StringUtil.equalsIgnoreCase(repo1.getUserName(), repo2.getUserName()); + } - private boolean equals(@NotNull GithubFullPath repo1, @Nullable GithubRepo repo2) { - if (repo2 == null) { - return false; - } - return StringUtil.equalsIgnoreCase(repo1.getUser(), repo2.getUserName()); - } - }.execute(); + private static boolean equals(@NotNull GithubFullPath repo1, @Nullable GithubRepo repo2) { + if (repo2 == null) { + return false; + } + return StringUtil.equalsIgnoreCase(repo1.getUser(), repo2.getUserName()); } private static class GithubInfo { @NotNull private final GithubRepoDetailed myRepo; @NotNull private final GithubAuthData myAuthData; + @NotNull private final List<String> myBranches; - private GithubInfo(@NotNull GithubAuthData authData, @NotNull GithubRepoDetailed repo) { + private GithubInfo(@NotNull GithubAuthData authData, @NotNull GithubRepoDetailed repo, @NotNull List<String> branches) { myAuthData = authData; myRepo = repo; + myBranches = branches; } @NotNull @@ -370,5 +356,10 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { public GithubAuthData getAuthData() { return myAuthData; } + + @NotNull + public List<String> getBranches() { + return myBranches; + } } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index e2f00946629f..bdbf6b0dc635 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -23,7 +23,6 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ThrowableConvertor; @@ -42,7 +41,9 @@ import git4idea.util.GitPreservingProcess; import icons.GithubIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.*; +import org.jetbrains.plugins.github.api.GithubApiUtil; +import org.jetbrains.plugins.github.api.GithubFullPath; +import org.jetbrains.plugins.github.api.GithubRepoDetailed; import java.io.IOException; import java.util.Collections; @@ -71,7 +72,7 @@ public class GithubRebaseAction extends DumbAwareAction { return; } - if (StringUtil.isEmptyOrSpaces(GithubSettings.getInstance().getLogin())) { + if (!GithubSettings.getInstance().isAuthConfigured()) { setVisibleEnabled(e, false, false); return; } @@ -115,6 +116,7 @@ public class GithubRebaseAction extends DumbAwareAction { new Task.Backgroundable(project, "Rebasing GitHub fork...") { @Override public void run(@NotNull ProgressIndicator indicator) { + gitRepository.update(); String upstreamRemoteUrl = GithubUtil.findUpstreamRemote(gitRepository); if (upstreamRemoteUrl == null) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java index 6ac53c59a92f..ebe8d6fb8831 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java @@ -23,9 +23,11 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubApiUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; import static org.jetbrains.plugins.github.GithubAuthData.AuthType; @@ -52,15 +54,15 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } public static class State { - public String LOGIN = ""; - public String HOST = GithubApiUtil.DEFAULT_GITHUB_HOST; - public AuthType AUTH_TYPE = AuthType.ANONYMOUS; + @Nullable public String LOGIN = null; + @NotNull public String HOST = GithubApiUtil.DEFAULT_GITHUB_HOST; + @NotNull public AuthType AUTH_TYPE = AuthType.ANONYMOUS; public boolean ANONYMOUS_GIST = false; public boolean OPEN_IN_BROWSER_GIST = true; public boolean PRIVATE_GIST = true; public boolean SAVE_PASSWORD = true; - public Collection<String> TRUSTED_HOSTS = new ArrayList<String>(); - public String CREATE_PULL_REQUEST_DEFAULT_BRANCH = ""; + @NotNull public Collection<String> TRUSTED_HOSTS = new ArrayList<String>(); + @Nullable public String CREATE_PULL_REQUEST_DEFAULT_BRANCH = null; } public static GithubSettings getInstance() { @@ -72,8 +74,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S return myState.HOST; } - // TODO return null if no login instead of empty string - @NotNull + @Nullable public String getLogin() { return StringUtil.notNullize(myState.LOGIN); } @@ -83,11 +84,15 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S return myState.AUTH_TYPE; } + public boolean isAuthConfigured() { + return !myState.AUTH_TYPE.equals(AuthType.ANONYMOUS); + } + private void setHost(@NotNull String host) { myState.HOST = StringUtil.notNullize(host, GithubApiUtil.DEFAULT_GITHUB_HOST); } - private void setLogin(@NotNull String login) { + private void setLogin(@Nullable String login) { myState.LOGIN = login; } @@ -116,7 +121,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S return passwordSafe.getSettings().getProviderType() == PasswordSafeSettings.ProviderType.MASTER_PASSWORD; } - @NotNull + @Nullable public String getCreatePullRequestDefaultBranch() { return myState.CREATE_PULL_REQUEST_DEFAULT_BRANCH; } @@ -203,13 +208,16 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S switch (auth.getAuthType()) { case BASIC: assert auth.getBasicAuth() != null; + setLogin(auth.getBasicAuth().getLogin()); setPassword(auth.getBasicAuth().getPassword(), rememberPassword); break; case TOKEN: assert auth.getTokenAuth() != null; + setLogin(null); setPassword(auth.getTokenAuth().getToken(), rememberPassword); break; case ANONYMOUS: + setLogin(null); setPassword("", rememberPassword); break; default: @@ -217,9 +225,8 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } } - public void setCredentials(@NotNull String host, @NotNull String login, @NotNull GithubAuthData auth, boolean rememberPassword) { + public void setCredentials(@NotNull String host, @NotNull GithubAuthData auth, boolean rememberPassword) { setHost(host); - setLogin(login); setAuthData(auth, rememberPassword); } }
\ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java index a6edc0229575..b961d421cd0b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java @@ -35,7 +35,8 @@ import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.*; +import org.jetbrains.plugins.github.api.GithubApiUtil; +import org.jetbrains.plugins.github.api.GithubUserDetailed; import org.jetbrains.plugins.github.ui.GithubBasicLoginDialog; import org.jetbrains.plugins.github.ui.GithubLoginDialog; @@ -109,12 +110,15 @@ public class GithubUtil { } @NotNull - public static <T> T runWithValidBasicAuth(@Nullable Project project, - @NotNull ProgressIndicator indicator, - @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { + public static <T> T runWithValidBasicAuthForHost(@Nullable Project project, + @NotNull ProgressIndicator indicator, + @NotNull String host, + @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException { + GithubSettings settings = GithubSettings.getInstance(); GithubAuthData auth; - if (GithubSettings.getInstance().getAuthType() == GithubAuthData.AuthType.BASIC) { - auth = GithubSettings.getInstance().getAuthData(); + if (settings.getAuthType() == GithubAuthData.AuthType.BASIC && + StringUtil.equalsIgnoreCase(GithubUrlUtil.getApiUrl(host), GithubUrlUtil.getApiUrl(settings.getHost()))) { + auth = settings.getAuthData(); } else { auth = GithubAuthData.createAnonymous(); @@ -126,7 +130,7 @@ public class GithubUtil { return task.convert(auth); } catch (GithubAuthenticationException e) { - auth = getValidBasicAuthData(project, indicator); + auth = getValidBasicAuthDataForHost(project, indicator, host); if (auth == null) { throw new GithubAuthenticationCanceledException("Can't get valid credentials"); } @@ -134,7 +138,7 @@ public class GithubUtil { } catch (IOException e) { if (checkSSLCertificate(e, auth.getHost(), indicator)) { - return runWithValidBasicAuth(project, indicator, task); + return runWithValidBasicAuthForHost(project, indicator, host, task); } throw e; } @@ -177,8 +181,11 @@ public class GithubUtil { * @return null if user canceled login dialog. Valid GithubAuthData otherwise. */ @Nullable - public static GithubAuthData getValidBasicAuthData(@Nullable Project project, @NotNull ProgressIndicator indicator) { + public static GithubAuthData getValidBasicAuthDataForHost(@Nullable Project project, + @NotNull ProgressIndicator indicator, + @NotNull String host) { final GithubLoginDialog dialog = new GithubBasicLoginDialog(project); + dialog.lockHost(host); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { @@ -232,12 +239,7 @@ public class GithubUtil { throw new GithubAuthenticationException("Anonymous connection not allowed"); } - try { - return testConnection(auth); - } - catch (JsonException e) { - throw new GithubAuthenticationException("Can't get user info", e); - } + return testConnection(auth); } @NotNull @@ -266,10 +268,10 @@ public class GithubUtil { if (GithubUrlUtil.isGithubUrl(remoteUrl)) { final String remoteName = gitRemote.getName(); if ("github".equals(remoteName) || "origin".equals(remoteName)) { - return new Pair<GitRemote, String>(gitRemote, remoteUrl); + return Pair.create(gitRemote, remoteUrl); } if (githubRemote == null) { - githubRemote = new Pair<GitRemote, String>(gitRemote, remoteUrl); + githubRemote = Pair.create(gitRemote, remoteUrl); } break; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/DataConstructor.java b/plugins/github/src/org/jetbrains/plugins/github/api/DataConstructor.java index d0005c12a858..20a957ccf746 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/DataConstructor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/DataConstructor.java @@ -19,9 +19,7 @@ import org.jetbrains.annotations.NotNull; /** * @author Aleksey Pivovarov - */ - -/** + * * All fields of the raw type are nullable by the nature of GSon parser; * but some of them are required, so we want them to be @NotNull in the actual data class, * otherwise there is an error in JSon data received from the server diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index 107476f56160..d83eec467cf7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -43,6 +43,7 @@ public class GithubApiUtil { public static final String DEFAULT_GITHUB_HOST = "github.com"; private static final int CONNECTION_TIMEOUT = 5000; + private static final String PER_PAGE = "per_page=100"; private static final Logger LOG = GithubUtil.LOG; private static final Header ACCEPT_HTML_BODY_MARKUP = new Header("Accept", "application/vnd.github.v3.html+json"); @@ -84,7 +85,7 @@ public class GithubApiUtil { private static ResponsePage request(@NotNull GithubAuthData auth, @NotNull String path, @Nullable String requestBody, - @Nullable Collection<Header> headers, + @NotNull Collection<Header> headers, @NotNull HttpVerb verb) throws IOException { HttpMethod method = null; try { @@ -128,7 +129,7 @@ public class GithubApiUtil { private static HttpMethod doREST(@NotNull final GithubAuthData auth, @NotNull String path, @Nullable final String requestBody, - @Nullable final Collection<Header> headers, + @NotNull final Collection<Header> headers, @NotNull final HttpVerb verb) throws IOException { HttpClient client = getHttpClient(auth.getBasicAuth()); String uri = GithubUrlUtil.getApiUrl(auth.getHost()) + path; @@ -160,10 +161,8 @@ public class GithubApiUtil { if (tokenAuth != null) { method.addRequestHeader("Authorization", "token " + tokenAuth.getToken()); } - if (headers != null) { - for (Header header : headers) { - method.addRequestHeader(header); - } + for (Header header : headers) { + method.addRequestHeader(header); } return method; } @@ -207,10 +206,9 @@ public class GithubApiUtil { case HttpStatus.SC_UNAUTHORIZED: case HttpStatus.SC_PAYMENT_REQUIRED: case HttpStatus.SC_FORBIDDEN: - case HttpStatus.SC_NOT_FOUND: throw new GithubAuthenticationException("Request response: " + getErrorMessage(method)); default: - throw new HttpException(code + ": " + getErrorMessage(method)); + throw new GithubStatusCodeException(code + ": " + getErrorMessage(method), code); } } @@ -375,7 +373,7 @@ public class GithubApiUtil { public static Collection<String> getTokenScopes(@NotNull GithubAuthData auth) throws IOException { HttpMethod method = null; try { - method = doREST(auth, "", null, null, HttpVerb.HEAD); + method = doREST(auth, "/user", null, Collections.<Header>emptyList(), HttpVerb.HEAD); checkStatusCode(method); @@ -410,6 +408,16 @@ public class GithubApiUtil { } @NotNull + public static String getReadOnlyToken(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @Nullable String note) + throws IOException { + GithubRepo repository = getDetailedRepoInfo(auth, user, repo); + + List<String> scopes = repository.isPrivate() ? Collections.singletonList("repo") : Collections.<String>emptyList(); + + return getScopedToken(auth, scopes, note); + } + + @NotNull public static GithubUser getCurrentUser(@NotNull GithubAuthData auth) throws IOException { JsonElement result = getRequest(auth, "/user"); return createDataFromRaw(fromJson(result, GithubUserRaw.class), GithubUser.class); @@ -433,7 +441,7 @@ public class GithubApiUtil { @NotNull private static List<GithubRepo> doGetAvailableRepos(@NotNull GithubAuthData auth, @Nullable String user) throws IOException { - String path = user == null ? "/user/repos" : "/users/" + user + "/repos?per_page=100"; + String path = user == null ? "/user/repos" : "/users/" + user + "/repos?" + PER_PAGE; PagedRequest<GithubRepo> request = new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class); @@ -509,10 +517,10 @@ public class GithubApiUtil { @Nullable String assigned) throws IOException { String path; if (StringUtil.isEmptyOrSpaces(assigned)) { - path = "/repos/" + user + "/" + repo + "/issues?per_page=100"; + path = "/repos/" + user + "/" + repo + "/issues?" + PER_PAGE; } else { - path = "/repos/" + user + "/" + repo + "/issues?assignee=" + assigned + "&per_page=100"; + path = "/repos/" + user + "/" + repo + "/issues?assignee=" + assigned + "&" + PER_PAGE; } PagedRequest<GithubIssue> request = new PagedRequest<GithubIssue>(path, GithubIssue.class, GithubIssueRaw[].class); @@ -521,7 +529,6 @@ public class GithubApiUtil { } @NotNull - public static List<GithubIssue> getIssuesQueried(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @@ -549,7 +556,7 @@ public class GithubApiUtil { @NotNull public static List<GithubIssueComment> getIssueComments(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id) throws IOException { - String path = "/repos/" + user + "/" + repo + "/issues/" + id + "/comments?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/issues/" + id + "/comments?" + PER_PAGE; PagedRequest<GithubIssueComment> request = new PagedRequest<GithubIssueComment>(path, GithubIssueComment.class, GithubIssueCommentRaw[].class, ACCEPT_HTML_BODY_MARKUP); @@ -579,7 +586,7 @@ public class GithubApiUtil { @NotNull public static List<GithubPullRequest> getPullRequests(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo) throws IOException { - String path = "/repos/" + user + "/" + repo + "/pulls?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/pulls?" + PER_PAGE; PagedRequest<GithubPullRequest> request = new PagedRequest<GithubPullRequest>(path, GithubPullRequest.class, GithubPullRequestRaw[].class, ACCEPT_HTML_BODY_MARKUP); @@ -589,7 +596,7 @@ public class GithubApiUtil { @NotNull public static PagedRequest<GithubPullRequest> getPullRequests(@NotNull String user, @NotNull String repo) { - String path = "/repos/" + user + "/" + repo + "/pulls?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/pulls?" + PER_PAGE; return new PagedRequest<GithubPullRequest>(path, GithubPullRequest.class, GithubPullRequestRaw[].class, ACCEPT_HTML_BODY_MARKUP); } @@ -597,7 +604,7 @@ public class GithubApiUtil { @NotNull public static List<GithubCommit> getPullRequestCommits(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id) throws IOException { - String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/commits?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/commits?" + PER_PAGE; PagedRequest<GithubCommit> request = new PagedRequest<GithubCommit>(path, GithubCommit.class, GithubCommitRaw[].class); @@ -607,7 +614,7 @@ public class GithubApiUtil { @NotNull public static List<GithubFile> getPullRequestFiles(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id) throws IOException { - String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/files?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/files?" + PER_PAGE; PagedRequest<GithubFile> request = new PagedRequest<GithubFile>(path, GithubFile.class, GithubFileRaw[].class); @@ -617,7 +624,7 @@ public class GithubApiUtil { @NotNull public static List<GithubBranch> getRepoBranches(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo) throws IOException { - String path = "/repos/" + user + "/" + repo + "/branches?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/branches?" + PER_PAGE; PagedRequest<GithubBranch> request = new PagedRequest<GithubBranch>(path, GithubBranch.class, GithubBranchRaw[].class); @@ -629,7 +636,7 @@ public class GithubApiUtil { @NotNull String user, @NotNull String repo, @NotNull String forkUser) throws IOException { - String path = "/repos/" + user + "/" + repo + "/forks?per_page=100"; + String path = "/repos/" + user + "/" + repo + "/forks?" + PER_PAGE; PagedRequest<GithubRepo> request = new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class); diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubStatusCodeException.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubStatusCodeException.java new file mode 100644 index 000000000000..3b15c000d900 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubStatusCodeException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github.api; + +import java.io.IOException; + +/** + * @author Aleksey Pivovarov + */ +public class GithubStatusCodeException extends IOException { + private final int myStatusCode; + + public GithubStatusCodeException(String message, int statusCode) { + super(message); + myStatusCode = statusCode; + } + + public int getStatusCode() { + return myStatusCode; + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index d2b4a8728ba1..df1fd7f38515 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -13,16 +13,19 @@ import com.intellij.util.ThrowableConvertor; import com.intellij.util.ui.FormBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.*; import org.jetbrains.plugins.github.GithubAuthData; +import org.jetbrains.plugins.github.GithubAuthenticationCanceledException; +import org.jetbrains.plugins.github.GithubNotifications; +import org.jetbrains.plugins.github.GithubUtil; import org.jetbrains.plugins.github.api.GithubApiUtil; import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; -import java.util.Collection; -import java.util.Collections; /** * @author Dennis.Ushakov @@ -34,7 +37,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor private JButton myTokenButton; private JBLabel myRepoAuthorLabel; private JBLabel myRepoLabel; - private JCheckBox myPrivateRepo; + private JBLabel myTokenLabel; public GithubRepositoryEditor(final Project project, final GithubRepository repository, Consumer<GithubRepository> changeListener) { super(project, repository, changeListener); @@ -42,11 +45,32 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor myUsernameLabel.setVisible(false); myPasswordText.setVisible(false); myPasswordLabel.setVisible(false); + myUseHttpAuthenticationCheckBox.setVisible(false); myToken.setText(repository.getToken()); myRepoAuthor.setText(repository.getRepoAuthor()); myRepoName.setText(repository.getRepoName()); - myPrivateRepo.setSelected(false); + + DocumentListener buttonUpdater = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + updateTokenButton(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTokenButton(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + updateTokenButton(); + } + }; + + myRepoAuthor.getDocument().addDocumentListener(buttonUpdater); + myRepoName.getDocument().addDocumentListener(buttonUpdater); + myURLText.getDocument().addDocumentListener(buttonUpdater); setAnchor(myRepoAuthorLabel); } @@ -56,7 +80,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor protected JComponent createCustomPanel() { myUrlLabel.setText("Host:"); - myRepoAuthorLabel = new JBLabel("Repository author:", SwingConstants.RIGHT); + myRepoAuthorLabel = new JBLabel("Repository Owner:", SwingConstants.RIGHT); myRepoAuthor = new JTextField(); installListener(myRepoAuthor); @@ -64,9 +88,10 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor myRepoName = new JTextField(); installListener(myRepoName); + myTokenLabel = new JBLabel("API Token:", SwingConstants.RIGHT); myToken = new JTextField(); installListener(myToken); - myTokenButton = new JButton("API token"); + myTokenButton = new JButton("Create API token"); myTokenButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { generateToken(); @@ -74,70 +99,39 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor } }); - myPrivateRepo = new JCheckBox("Private repository"); - installListener(myPrivateRepo); + JPanel myTokenPanel = new JPanel(); + myTokenPanel.setLayout(new BorderLayout(5, 5)); + myTokenPanel.add(myToken, BorderLayout.CENTER); + myTokenPanel.add(myTokenButton, BorderLayout.EAST); - return FormBuilder.createFormBuilder().setAlignLabelOnRight(true).addLabeledComponent(myTokenButton, myToken) - .addLabeledComponent(myRepoAuthorLabel, myRepoAuthor).addLabeledComponent(myRepoLabel, myRepoName) - .addComponentToRightColumn(myPrivateRepo).getPanel(); + return FormBuilder.createFormBuilder().setAlignLabelOnRight(true).addLabeledComponent(myRepoAuthorLabel, myRepoAuthor) + .addLabeledComponent(myRepoLabel, myRepoName).addLabeledComponent(myTokenLabel, myTokenPanel).getPanel(); } @Override public void apply() { - myRepository.setRepoName(myRepoName.getText().trim()); - myRepository.setRepoAuthor(myRepoAuthor.getText().trim()); - myRepository.setToken(myToken.getText().trim()); - myUseHttpAuthenticationCheckBox.setSelected(!StringUtil.isEmpty(myUserNameText.getText())); + myRepository.setRepoName(getRepoName()); + myRepository.setRepoAuthor(getRepoAuthor()); + myRepository.setToken(getToken()); super.apply(); } - @Override - protected void afterTestConnection(final boolean connectionSuccessful) { - if (connectionSuccessful) { - final Ref<Collection<String>> scopesRef = new Ref<Collection<String>>(); - final Ref<IOException> exceptionRef = new Ref<IOException>(); - ProgressManager.getInstance().run(new Task.Modal(myProject, "Access to GitHub", true) { - public void run(@NotNull ProgressIndicator indicator) { - try { - scopesRef - .set(GithubApiUtil.getTokenScopes(GithubAuthData.createTokenAuth(myURLText.getText().trim(), myToken.getText().trim()))); - } - catch (IOException e) { - exceptionRef.set(e); - } - } - }); - if (!exceptionRef.isNull()) { - GithubNotifications.showErrorDialog(myProject, "Can't check token scopes", exceptionRef.get()); - return; - } - Collection<String> scopes = scopesRef.get(); - if (myPrivateRepo.isSelected()) { - scopes.remove("repo"); - } - if (scopes.isEmpty()) { - return; - } - GithubNotifications - .showWarningDialog(myProject, "Unneeded token scopes detected", "Unneeded scopes: " + StringUtil.join(scopes, ", ")); - } - } - private void generateToken() { final Ref<String> tokenRef = new Ref<String>(); final Ref<IOException> exceptionRef = new Ref<IOException>(); - final Collection<String> scopes = myPrivateRepo.isSelected() ? Collections.singleton("repo") : Collections.<String>emptyList(); ProgressManager.getInstance().run(new Task.Modal(myProject, "Access to GitHub", true) { public void run(@NotNull ProgressIndicator indicator) { try { - tokenRef.set(GithubUtil.runWithValidBasicAuth(myProject, indicator, new ThrowableConvertor<GithubAuthData, String, IOException>() { - @Nullable - @Override - public String convert(GithubAuthData auth) throws IOException { - return GithubApiUtil.getScopedToken(auth, scopes, "Intellij tasks plugin"); - - } - })); + tokenRef.set(GithubUtil.runWithValidBasicAuthForHost(myProject, indicator, getHost(), + new ThrowableConvertor<GithubAuthData, String, IOException>() { + @NotNull + @Override + public String convert(GithubAuthData auth) throws IOException { + return GithubApiUtil + .getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), + "Intellij tasks plugin"); + } + })); } catch (IOException e) { exceptionRef.set(e); @@ -159,5 +153,37 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor super.setAnchor(anchor); myRepoAuthorLabel.setAnchor(anchor); myRepoLabel.setAnchor(anchor); + myTokenLabel.setAnchor(anchor); + } + + private void updateTokenButton() { + if (StringUtil.isEmptyOrSpaces(getHost()) || + StringUtil.isEmptyOrSpaces(getRepoAuthor()) || + StringUtil.isEmptyOrSpaces(getRepoName())) { + myTokenButton.setEnabled(false); + } + else { + myTokenButton.setEnabled(true); + } + } + + @NotNull + private String getHost() { + return myURLText.getText().trim(); + } + + @NotNull + private String getRepoAuthor() { + return myRepoAuthor.getText().trim(); + } + + @NotNull + private String getRepoName() { + return myRepoName.getText().trim(); + } + + @NotNull + private String getToken() { + return myToken.getText().trim(); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java index 3395d7247874..da9a7e9ef63b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubBasicLoginDialog.java @@ -34,8 +34,7 @@ public class GithubBasicLoginDialog extends GithubLoginDialog { protected void saveCredentials(GithubAuthData auth) { final GithubSettings settings = GithubSettings.getInstance(); if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { - settings - .setCredentials(myGithubLoginPanel.getHost(), myGithubLoginPanel.getLogin(), auth, myGithubLoginPanel.isSavePasswordSelected()); + settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); } } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistDialog.java index 259cb393a77f..4e9a70a83559 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistDialog.java @@ -32,7 +32,7 @@ import javax.swing.*; public class GithubCreateGistDialog extends DialogWrapper { private final GithubCreateGistPanel myGithubCreateGistPanel; - public GithubCreateGistDialog(@NotNull final Project project, @Nullable Editor editor, @Nullable VirtualFile file) { + public GithubCreateGistDialog(@NotNull final Project project, @Nullable Editor editor, @Nullable VirtualFile[] files, @Nullable VirtualFile file) { super(project, true); myGithubCreateGistPanel = new GithubCreateGistPanel(); // Use saved settings for controls @@ -41,21 +41,27 @@ public class GithubCreateGistDialog extends DialogWrapper { myGithubCreateGistPanel.setPrivate(settings.isPrivateGist()); myGithubCreateGistPanel.setOpenInBrowser(settings.isOpenInBrowserGist()); - if (file != null && !file.isDirectory()) { - myGithubCreateGistPanel.showFileNameField(file.getName()); + if (editor != null) { + if (file != null) { + myGithubCreateGistPanel.showFileNameField(file.getName()); + } + else { + myGithubCreateGistPanel.showFileNameField(""); + } + } + else if (files != null) { + if (files.length == 1 && !files[0].isDirectory()) { + myGithubCreateGistPanel.showFileNameField(files[0].getName()); + } } - else if (editor != null) { - myGithubCreateGistPanel.showFileNameField(""); + else if (file != null && !file.isDirectory()) { + myGithubCreateGistPanel.showFileNameField(file.getName()); } + setTitle("Create Gist"); init(); } - @NotNull - protected Action[] createActions() { - return new Action[] {getOKAction(), getCancelAction(), getHelpAction()}; - } - @Override protected JComponent createCenterPanel() { return myGithubCreateGistPanel.getPanel(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistPanel.form index bc2c02451e28..5b6207c7257a 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreateGistPanel.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubCreateGistPanel"> - <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="20" y="20" width="500" height="400"/> @@ -8,19 +8,6 @@ <properties/> <border type="none"/> <children> - <vspacer id="1202b"> - <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> - </constraints> - </vspacer> - <component id="51bc1" class="javax.swing.JTextArea" binding="myDescriptionTextArea"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="4" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="50"/> - </grid> - </constraints> - <properties/> - </component> <component id="b0e4d" class="javax.swing.JLabel"> <constraints> <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> @@ -74,6 +61,22 @@ </constraints> <properties/> </component> + <scrollpane id="6c5d2" class="com.intellij.ui.components.JBScrollPane"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="4" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"> + <minimum-size width="150" height="50"/> + <preferred-size width="150" height="50"/> + </grid> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="51bc1" class="javax.swing.JTextArea" binding="myDescriptionTextArea"> + <constraints/> + <properties/> + </component> + </children> + </scrollpane> </children> </grid> </form> diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 8308b3dfcf9f..32e6184040b5 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -26,6 +26,7 @@ import org.jetbrains.plugins.github.GithubSettings; import javax.swing.*; import java.util.Collection; +import java.util.List; import java.util.regex.Pattern; /** @@ -35,11 +36,14 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { private final GithubCreatePullRequestPanel myGithubCreatePullRequestPanel; private static final Pattern GITHUB_REPO_PATTERN = Pattern.compile("[a-zA-Z0-9_.-]+:[a-zA-Z0-9_.-]+"); - public GithubCreatePullRequestDialog(@NotNull final Project project) { + public GithubCreatePullRequestDialog(@NotNull final Project project, @NotNull List<String> branches, @Nullable String suggestedBranch) { super(project, true); myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(); - myGithubCreatePullRequestPanel.setBranch(GithubSettings.getInstance().getCreatePullRequestDefaultBranch()); + myGithubCreatePullRequestPanel.setBranches(branches); + + String configBranch = GithubSettings.getInstance().getCreatePullRequestDefaultBranch(); + myGithubCreatePullRequestPanel.setSelectedBranch(configBranch != null ? configBranch : suggestedBranch); setTitle("Create Pull Request"); init(); @@ -83,14 +87,6 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { GithubSettings.getInstance().setCreatePullRequestDefaultBranch(getTargetBranch()); } - public void addBranches(@NotNull Collection<String> branches) { - myGithubCreatePullRequestPanel.addBranches(branches); - } - - public void setBusy(boolean busy) { - myGithubCreatePullRequestPanel.setBusy(busy); - } - @Nullable @Override protected ValidationInfo doValidate() { @@ -111,6 +107,6 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @TestOnly public void setBranch(String branch) { - myGithubCreatePullRequestPanel.setBranch(branch); + myGithubCreatePullRequestPanel.setSelectedBranch(branch); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index cf528f8ed93c..e5dda901b53e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubCreatePullRequestPanel"> - <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <xy x="20" y="20" width="500" height="400"/> @@ -34,21 +34,13 @@ </component> <component id="996e9" class="javax.swing.JTextField" binding="myTitleTextField"> <constraints> - <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties/> </component> - <component id="21aa4" class="javax.swing.JTextArea" binding="myDescriptionTextArea"> - <constraints> - <grid row="3" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="50"/> - </grid> - </constraints> - <properties/> - </component> - <component id="78a64" class="javax.swing.JComboBox" binding="myBranchComboBox"> + <component id="78a64" class="com.intellij.openapi.ui.ComboBox" binding="myBranchComboBox"> <constraints> <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/> </constraints> @@ -57,17 +49,21 @@ <toolTipText value="Target branch in format 'user:branch', where user - owner of the target repository"/> </properties> </component> - <vspacer id="2ad8"> + <scrollpane id="61e54" class="com.intellij.ui.components.JBScrollPane"> <constraints> - <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> - </constraints> - </vspacer> - <component id="5be7e" class="com.intellij.util.ui.AsyncProcessIcon" binding="myAsyncProcessIcon" custom-create="true"> - <constraints> - <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/> + <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"> + <minimum-size width="150" height="50"/> + </grid> </constraints> <properties/> - </component> + <border type="none"/> + <children> + <component id="21aa4" class="javax.swing.JTextArea" binding="myDescriptionTextArea"> + <constraints/> + <properties/> + </component> + </children> + </scrollpane> </children> </grid> </form> diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java index 1714e85fe36f..a178024d1911 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java @@ -15,13 +15,15 @@ */ package org.jetbrains.plugins.github.ui; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ui.AsyncProcessIcon; +import com.intellij.ui.SortedComboBoxModel; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collection; -import java.util.HashSet; +import java.util.Comparator; /** * @author Aleksey Pivovarov @@ -29,12 +31,19 @@ import java.util.HashSet; public class GithubCreatePullRequestPanel { private JTextField myTitleTextField; private JTextArea myDescriptionTextArea; - private JComboBox myBranchComboBox; + private ComboBox myBranchComboBox; + private SortedComboBoxModel<String> myBranchModel; private JPanel myPanel; - private AsyncProcessIcon myAsyncProcessIcon; public GithubCreatePullRequestPanel() { myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder()); + myBranchModel = new SortedComboBoxModel<String>(new Comparator<String>() { + @Override + public int compare(String o1, String o2) { + return StringUtil.naturalCompare(o1, o2); + } + }); + myBranchComboBox.setModel(myBranchModel); } @NotNull @@ -52,30 +61,18 @@ public class GithubCreatePullRequestPanel { return myBranchComboBox.getSelectedItem().toString(); } - public void setBranch(@NotNull String branch) { + public void setSelectedBranch(@Nullable String branch) { if (StringUtil.isEmptyOrSpaces(branch)) { + myBranchComboBox.setSelectedItem(""); return; } - for (int i = 0; i < myBranchComboBox.getItemCount(); i++) { - Object element = myBranchComboBox.getItemAt(i); - if (branch.equals(element)) { - myBranchComboBox.setSelectedItem(element); - return; - } - } - myBranchComboBox.addItem(branch); myBranchComboBox.setSelectedItem(branch); } - public void addBranches(@NotNull Collection<String> branches) { - HashSet<Object> set = new HashSet<Object>(branches); - for (int i = 0; i < myBranchComboBox.getItemCount(); i++) { - set.remove(myBranchComboBox.getItemAt(i)); - } - for (Object element : set) { - myBranchComboBox.addItem(element); - } + public void setBranches(@NotNull Collection<String> branches) { + myBranchModel.clear(); + myBranchModel.addAll(branches); } public JPanel getPanel() { @@ -87,15 +84,6 @@ public class GithubCreatePullRequestPanel { return myTitleTextField; } - public void setBusy(boolean busy) { - if (busy) { - myAsyncProcessIcon.resume(); - } - else { - myAsyncProcessIcon.suspend(); - } - } - public JComboBox getComboBox() { return myBranchComboBox; } @@ -107,8 +95,4 @@ public class GithubCreatePullRequestPanel { public void setTitle(String title) { myTitleTextField.setText(title); } - - private void createUIComponents() { - myAsyncProcessIcon = new AsyncProcessIcon("Loading available branches"); - } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java index 402cb4eb1a9a..e7968be7b7df 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginDialog.java @@ -6,10 +6,8 @@ import com.intellij.openapi.ui.DialogWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.GithubAuthData; -import org.jetbrains.plugins.github.GithubAuthenticationException; import org.jetbrains.plugins.github.GithubSettings; import org.jetbrains.plugins.github.GithubUtil; -import org.jetbrains.plugins.github.api.GithubUserDetailed; import javax.swing.*; import java.io.IOException; @@ -70,12 +68,7 @@ public class GithubLoginDialog extends DialogWrapper { protected void doOKAction() { final GithubAuthData auth = myGithubLoginPanel.getAuthData(); try { - GithubUserDetailed user = GithubUtil.checkAuthData(auth); - if (!myGithubLoginPanel.getLogin().equalsIgnoreCase(user.getLogin())) { - myGithubLoginPanel.setLogin(user.getLogin()); - setErrorText("Login doesn't match credentials. Fixed"); - return; - } + GithubUtil.checkAuthData(auth); saveCredentials(auth); if (mySettings.isSavePasswordMakesSense()) { @@ -91,7 +84,7 @@ public class GithubLoginDialog extends DialogWrapper { protected void saveCredentials(GithubAuthData auth) { final GithubSettings settings = GithubSettings.getInstance(); - settings.setCredentials(myGithubLoginPanel.getHost(), myGithubLoginPanel.getLogin(), auth, myGithubLoginPanel.isSavePasswordSelected()); + settings.setCredentials(myGithubLoginPanel.getHost(), auth, myGithubLoginPanel.isSavePasswordSelected()); } public void clearErrors() { @@ -102,4 +95,8 @@ public class GithubLoginDialog extends DialogWrapper { public GithubAuthData getAuthData() { return myGithubLoginPanel.getAuthData(); } + + public void lockHost(String host) { + myGithubLoginPanel.lockHost(host); + } }
\ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form index 7dad2a149ac9..eedbe5e17b00 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form @@ -3,29 +3,13 @@ <grid id="27dc6" binding="myPane" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="500" height="168"/> + <xy x="20" y="20" width="500" height="174"/> </constraints> <properties> <focusable value="false"/> </properties> <border type="none"/> <children> - <component id="e76ec" class="javax.swing.JTextField" binding="myLoginTextField"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties/> - </component> - <component id="c0234" class="javax.swing.JLabel"> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Login:"/> - </properties> - </component> <component id="28ddd" class="javax.swing.JTextPane" binding="mySignupTextField"> <constraints> <grid row="4" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> @@ -71,7 +55,7 @@ </component> <component id="f851a" class="javax.swing.JComboBox" binding="myAuthTypeComboBox"> <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false"/> + <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties> <model/> @@ -80,7 +64,7 @@ </component> <component id="b466f" class="javax.swing.JCheckBox" binding="mySavePasswordCheckBox"> <constraints> - <grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"> + <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"> <preferred-size width="120" height="-1"/> </grid> </constraints> @@ -91,7 +75,7 @@ </component> <component id="325bb" class="javax.swing.JLabel"> <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Auth type:"/> @@ -105,6 +89,22 @@ <text value="Password:"/> </properties> </component> + <component id="e76ec" class="javax.swing.JTextField" binding="myLoginTextField"> + <constraints> + <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties/> + </component> + <component id="c0234" class="javax.swing.JLabel" binding="myLoginLabel"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Login:"/> + </properties> + </component> </children> </grid> </form> diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.java index 226265546db1..ea565e03c5c9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.java @@ -21,6 +21,7 @@ import com.intellij.ui.HyperlinkAdapter; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.table.ComponentsListFocusTraversalPolicy; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.GithubAuthData; import org.jetbrains.plugins.github.GithubUtil; @@ -31,7 +32,7 @@ import javax.swing.event.HyperlinkEvent; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.*; +import java.util.ArrayList; import java.util.List; /** @@ -47,6 +48,7 @@ public class GithubLoginPanel { private JCheckBox mySavePasswordCheckBox; private JComboBox myAuthTypeComboBox; private JLabel myPasswordLabel; + private JLabel myLoginLabel; private final static String AUTH_PASSWORD = "Password"; private final static String AUTH_TOKEN = "Token"; @@ -79,8 +81,21 @@ public class GithubLoginPanel { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { String item = e.getItem().toString(); - myPasswordLabel.setText(item + ":"); - mySavePasswordCheckBox.setText("Save " + item.toLowerCase()); + if (AUTH_PASSWORD.equals(item)) { + myPasswordLabel.setText("Password:"); + mySavePasswordCheckBox.setText("Save password"); + myLoginLabel.setVisible(true); + myLoginTextField.setVisible(true); + } + if (AUTH_TOKEN.equals(item)) { + myPasswordLabel.setText("Token:"); + mySavePasswordCheckBox.setText("Save token"); + myLoginLabel.setVisible(false); + myLoginTextField.setVisible(false); + } + if (dialog.isShowing()) { + dialog.pack(); + } } } }); @@ -103,7 +118,7 @@ public class GithubLoginPanel { myHostTextField.setText(host); } - public void setLogin(@NotNull String login) { + public void setLogin(@Nullable String login) { myLoginTextField.setText(login); } @@ -125,6 +140,11 @@ public class GithubLoginPanel { myAuthTypeComboBox.setEnabled(false); } + public void lockHost(@NotNull String host) { + setHost(host); + myHostTextField.setEnabled(false); + } + public void setSavePasswordSelected(boolean savePassword) { mySavePasswordCheckBox.setSelected(savePassword); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsConfigurable.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsConfigurable.java index 03e3b08801ef..f4c312d11b13 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsConfigurable.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsConfigurable.java @@ -46,7 +46,7 @@ public class GithubSettingsConfigurable implements SearchableConfigurable, VcsCo public void apply() throws ConfigurationException { if (mySettingsPane != null) { - mySettings.setCredentials(mySettingsPane.getHost(), mySettingsPane.getLogin(), mySettingsPane.getAuthData(), true); + mySettings.setCredentials(mySettingsPane.getHost(), mySettingsPane.getAuthData(), true); mySettingsPane.resetCredentialsModification(); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.form index 81400ae3000e..cc283855bc64 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.form @@ -16,7 +16,7 @@ </constraints> <properties/> </component> - <component id="c0234" class="javax.swing.JLabel"> + <component id="c0234" class="javax.swing.JLabel" binding="myLoginLabel"> <constraints> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java index c6a18378802e..54e1f61b1a14 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java @@ -22,8 +22,12 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.HyperlinkAdapter; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.github.*; -import org.jetbrains.plugins.github.api.GithubUserDetailed; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.github.GithubAuthData; +import org.jetbrains.plugins.github.GithubAuthenticationException; +import org.jetbrains.plugins.github.GithubSettings; +import org.jetbrains.plugins.github.GithubUtil; +import org.jetbrains.plugins.github.api.GithubUser; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -53,6 +57,7 @@ public class GithubSettingsPanel { private JButton myTestButton; private JTextField myHostTextField; private JComboBox myAuthTypeComboBox; + private JLabel myLoginLabel; private boolean myCredentialsModified; @@ -71,19 +76,17 @@ public class GithubSettingsPanel { myAuthTypeComboBox.addItem(AUTH_PASSWORD); myAuthTypeComboBox.addItem(AUTH_TOKEN); - reset(); - myTestButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { - GithubUserDetailed user = GithubUtil.checkAuthData(getAuthData()); - if (!getLogin().equalsIgnoreCase(user.getLogin())) { - setLogin(user.getLogin()); - Messages.showInfoMessage(myPane, "Login doesn't match credentials. Fixed", "Success"); - return; + GithubUser user = GithubUtil.checkAuthData(getAuthData()); + if (GithubAuthData.AuthType.TOKEN.equals(getAuthType())) { + Messages.showInfoMessage(myPane, "Connection successful for user " + user.getLogin(), "Success"); + } + else { + Messages.showInfoMessage(myPane, "Connection successful", "Success"); } - Messages.showInfoMessage(myPane, "Connection successful", "Success"); } catch (GithubAuthenticationException ex) { Messages.showErrorDialog(myPane, "Can't login using given credentials: " + ex.getMessage(), "Login Failure"); @@ -116,24 +119,21 @@ public class GithubSettingsPanel { @Override public void insertUpdate(DocumentEvent e) { if (!myCredentialsModified) { - setPassword(""); - myCredentialsModified = true; + erasePassword(); } } @Override public void removeUpdate(DocumentEvent e) { if (!myCredentialsModified) { - setPassword(""); - myCredentialsModified = true; + erasePassword(); } } @Override public void changedUpdate(DocumentEvent e) { if (!myCredentialsModified) { - setPassword(""); - myCredentialsModified = true; + erasePassword(); } } }; @@ -145,8 +145,7 @@ public class GithubSettingsPanel { @Override public void focusGained(FocusEvent e) { if (!myCredentialsModified && !getPassword().isEmpty()) { - setPassword(""); - myCredentialsModified = true; + erasePassword(); } } @@ -158,10 +157,28 @@ public class GithubSettingsPanel { myAuthTypeComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { - setPassword(""); - myCredentialsModified = true; + if (e.getStateChange() == ItemEvent.SELECTED) { + String item = e.getItem().toString(); + if (AUTH_PASSWORD.equals(item)) { + myLoginLabel.setVisible(true); + myLoginTextField.setVisible(true); + } + if (AUTH_TOKEN.equals(item)) { + myLoginLabel.setVisible(false); + myLoginTextField.setVisible(false); + } + myPane.validate(); + erasePassword(); + } } }); + + reset(); + } + + private void erasePassword() { + setPassword(""); + myCredentialsModified = true; } public JComponent getPanel() { @@ -182,7 +199,7 @@ public class GithubSettingsPanel { myHostTextField.setText(host); } - public void setLogin(@NotNull final String login) { + public void setLogin(@Nullable final String login) { myLoginTextField.setText(login); } @@ -232,18 +249,15 @@ public class GithubSettingsPanel { } public void reset() { - String login = mySettings.getLogin(); setHost(mySettings.getHost()); - setLogin(login); - setPassword(login.isEmpty() ? "" : DEFAULT_PASSWORD_TEXT); + setLogin(mySettings.getLogin()); + setPassword(mySettings.isAuthConfigured() ? DEFAULT_PASSWORD_TEXT : ""); setAuthType(mySettings.getAuthType()); resetCredentialsModification(); } public boolean isModified() { - return !Comparing.equal(mySettings.getHost(), getHost()) || - !Comparing.equal(mySettings.getLogin(), getLogin()) || - myCredentialsModified; + return !Comparing.equal(mySettings.getHost(), getHost()) || myCredentialsModified; } public void resetCredentialsModification() { diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java index b3c04d8ec2f0..53843019d3f2 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java @@ -52,4 +52,19 @@ public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase checkRemoteConfigured(); checkLastCommitPushed(); } + + public void testCommitRef1() throws Exception { + registerDefaultCreatePullRequestDialogHandler(myLogin1 + ":refs/heads/master"); + + cd(myProjectRoot.getPath()); + cloneRepo(); + createBranch(); + createChanges(); + + GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot); + + checkNotification(NotificationType.INFORMATION, "Successfully created pull request", null); + checkRemoteConfigured(); + checkLastCommitPushed(); + } } diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index 21c78af951dd..ee5233c8057e 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -173,7 +173,7 @@ public abstract class GithubTest extends UsefulTestCase { myAuth = GithubAuthData.createBasicAuth(host, login1, password); myGitHubSettings = GithubSettings.getInstance(); - myGitHubSettings.setCredentials(myHost, myLogin1, myAuth, false); + myGitHubSettings.setCredentials(myHost, myAuth, false); myDialogManager = (TestDialogManager)ServiceManager.getService(DialogManager.class); myNotificator = (TestNotificator)ServiceManager.getService(myProject, Notificator.class); diff --git a/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java b/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java index 2e7dae2262ea..5e2d5ead054d 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java @@ -69,6 +69,8 @@ import com.intellij.packaging.impl.artifacts.ArtifactUtil; import com.intellij.packaging.impl.compiler.ArtifactCompileScope; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime; +import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; import com.intellij.util.net.HttpConfigurable; import com.intellij.util.xml.GenericDomValue; import org.jetbrains.annotations.NotNull; @@ -90,40 +92,39 @@ public class AppEngineUploader { private final AppEngineSdk mySdk; private final String myEmail; private final String myPassword; + private final ServerRuntimeInstance.DeploymentOperationCallback myCallback; - private AppEngineUploader(Project project, - Artifact artifact, - AppEngineFacet appEngineFacet, - AppEngineSdk sdk, - String email, - String password) { + private AppEngineUploader(Project project, Artifact artifact, AppEngineFacet appEngineFacet, AppEngineSdk sdk, String email, + String password, ServerRuntimeInstance.DeploymentOperationCallback callback) { myProject = project; myArtifact = artifact; myAppEngineFacet = appEngineFacet; mySdk = sdk; myEmail = email; myPassword = password; + myCallback = callback; } @Nullable public static AppEngineUploader createUploader(@NotNull Project project, @NotNull Artifact artifact, - @Nullable AppEngineServerConfiguration configuration) { + @Nullable AppEngineServerConfiguration configuration, + ServerRuntimeInstance.DeploymentOperationCallback callback) { final String explodedPath = artifact.getOutputPath(); if (explodedPath == null) { - Messages.showErrorDialog(project, "Output path isn't specified for '" + artifact.getName() + "' artifact", CommonBundle.getErrorTitle()); + callback.errorOccurred("Output path isn't specified for '" + artifact.getName() + "' artifact"); return null; } final AppEngineFacet appEngineFacet = AppEngineUtil.findAppEngineFacet(project, artifact); if (appEngineFacet == null) { - Messages.showErrorDialog(project, "App Engine facet not found in '" + artifact.getName() + "' artifact", CommonBundle.getErrorTitle()); + callback.errorOccurred("App Engine facet not found in '" + artifact.getName() + "' artifact"); return null; } final AppEngineSdk sdk = appEngineFacet.getSdk(); if (!sdk.getAppCfgFile().exists()) { - Messages.showErrorDialog(project, "Path to App Engine SDK isn't specified correctly in App Engine Facet settings", CommonBundle.getErrorTitle()); + callback.errorOccurred("Path to App Engine SDK isn't specified correctly in App Engine Facet settings"); return null; } @@ -169,7 +170,7 @@ public class AppEngineUploader { password = dialog.getPassword(); } - return new AppEngineUploader(project, artifact, appEngineFacet, sdk, email, password); + return new AppEngineUploader(project, artifact, appEngineFacet, sdk, email, password, callback); } public void startUploading() { @@ -235,7 +236,7 @@ public class AppEngineUploader { process = commandLine.createProcess(); } catch (ExecutionException e) { - Messages.showErrorDialog(myProject, "Cannot start uploading: " + e.getMessage(), CommonBundle.getErrorTitle()); + myCallback.errorOccurred("Cannot start uploading: " + e.getMessage()); return; } @@ -281,5 +282,12 @@ public class AppEngineUploader { } } } + + @Override + public void processTerminated(ProcessEvent event) { + if (event.getExitCode() == 0) { + myCallback.succeeded(new DeploymentRuntime()); + } + } } } diff --git a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java index 15fb4051d1db..fe7f71dbb51b 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java @@ -24,6 +24,9 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.packaging.artifacts.Artifact; +import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime; +import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -57,7 +60,17 @@ public class UploadApplicationAction extends AnAction { return; } } - final AppEngineUploader uploader = AppEngineUploader.createUploader(project, artifact, null); + final AppEngineUploader uploader = AppEngineUploader.createUploader(project, artifact, null, new ServerRuntimeInstance.DeploymentOperationCallback() { + @Override + public void succeeded(@NotNull DeploymentRuntime deployment) { + + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + Messages.showErrorDialog(project, errorMessage, CommonBundle.getErrorTitle()); + } + }); if (uploader != null) { uploader.startUploading(); } diff --git a/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java b/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java index a7b798c6df2e..b69b47a034fe 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java @@ -25,10 +25,12 @@ import com.intellij.packaging.artifacts.Artifact; import com.intellij.packaging.artifacts.ArtifactPointerManager; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.deployment.*; +import com.intellij.remoteServer.runtime.Deployment; import com.intellij.remoteServer.runtime.ServerConnector; import com.intellij.remoteServer.runtime.ServerTaskExecutor; import com.intellij.remoteServer.runtime.deployment.DeploymentTask; import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.FormBuilder; import icons.GoogleAppEngineIcons; import org.jetbrains.annotations.NotNull; @@ -181,15 +183,15 @@ public class AppEngineCloudType extends ServerType<AppEngineServerConfiguration> Artifact artifact = ((ArtifactDeploymentSource)task.getSource()).getArtifact(); if (artifact == null) return; - AppEngineUploader uploader = AppEngineUploader.createUploader(task.getProject(), artifact, myConfiguration); + AppEngineUploader uploader = AppEngineUploader.createUploader(task.getProject(), artifact, myConfiguration, callback); if (uploader != null) { uploader.startUploading(); } } @Override - public void undeploy(@NotNull DeploymentTask<DummyDeploymentConfiguration> task, - @NotNull DeploymentOperationCallback callback) { + public void computeDeployments(@NotNull ComputeDeploymentsCallback deployments) { + deployments.succeeded(ContainerUtil.<Deployment>emptyList()); } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/AbstractMvcPsiNodeDescriptor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/AbstractMvcPsiNodeDescriptor.java index e1639e4b0774..b7e19ba80012 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/AbstractMvcPsiNodeDescriptor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/AbstractMvcPsiNodeDescriptor.java @@ -10,7 +10,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -59,6 +59,7 @@ public abstract class AbstractMvcPsiNodeDescriptor extends AbstractPsiBasedNode< return super.contains(file); } + @Override @Nullable protected PsiElement extractPsiFromValue() { final NodeId nodeId = getValue(); @@ -86,15 +87,10 @@ public abstract class AbstractMvcPsiNodeDescriptor extends AbstractPsiBasedNode< if (!isValid()) { return null; } - final PsiElement psiElement = extractPsiFromValue(); - assert psiElement != null; - - if (psiElement instanceof PsiFileSystemItem) { - return ((PsiFileSystemItem)psiElement).getVirtualFile(); - } - return psiElement.getContainingFile().getVirtualFile(); + return PsiUtilCore.getVirtualFile(extractPsiFromValue()); } + @Override protected void updateImpl(final PresentationData data) { final PsiElement psiElement = extractPsiFromValue(); if (psiElement instanceof NavigationItem) { @@ -110,14 +106,17 @@ public abstract class AbstractMvcPsiNodeDescriptor extends AbstractPsiBasedNode< return myWeight; } + @Override protected boolean hasProblemFileBeneath() { return WolfTheProblemSolver.getInstance(getProject()).hasProblemFilesBeneath(new Condition<VirtualFile>() { + @Override public boolean value(final VirtualFile virtualFile) { return contains(virtualFile); } }); } + @Override public boolean isValid() { final PsiElement psiElement = extractPsiFromValue(); return psiElement != null && psiElement.isValid(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectViewPane.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectViewPane.java index 6af5356a51aa..e50be1749d92 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectViewPane.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/MvcProjectViewPane.java @@ -34,11 +34,11 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.actions.ModuleDeleteProvider; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; @@ -169,19 +169,23 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id toolWindow.setTitleActions(new AnAction[]{new ScrollFromSourceAction(), collapseAction}); } + @Override public String getTitle() { throw new UnsupportedOperationException(); } + @Override public Icon getIcon() { return myDescriptor.getFramework().getIcon(); } + @Override @NotNull public String getId() { return myId; } + @Override public int getWeight() { throw new UnsupportedOperationException(); } @@ -191,6 +195,7 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id throw new UnsupportedOperationException(); } + @Override public SelectInTarget createSelectInTarget() { throw new UnsupportedOperationException(); } @@ -199,12 +204,14 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id @Override protected BaseProjectTreeBuilder createBuilder(final DefaultTreeModel treeModel) { return new ProjectTreeBuilder(myProject, myTree, treeModel, null, (ProjectAbstractTreeStructureBase)myTreeStructure) { + @Override protected AbstractTreeUpdater createUpdater() { return createTreeUpdater(this); } }; } + @Override protected ProjectAbstractTreeStructureBase createStructure() { final Project project = myProject; final String id = getId(); @@ -215,28 +222,33 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id return myViewState.hideEmptyMiddlePackages; } + @Override protected AbstractTreeNode createRoot(final Project project, ViewSettings settings) { return new MvcProjectNode(project, this, myDescriptor); } }; } + @Override protected ProjectViewTree createTree(final DefaultTreeModel treeModel) { return new ProjectViewTree(myProject, treeModel) { public String toString() { return myDescriptor.getFramework().getDisplayName() + " " + super.toString(); } + @Override public DefaultMutableTreeNode getSelectedNode() { return MvcProjectViewPane.this.getSelectedNode(); } }; } + @Override protected AbstractTreeUpdater createTreeUpdater(final AbstractTreeBuilder treeBuilder) { return new AbstractTreeUpdater(treeBuilder); } + @Override @Nullable protected PsiElement getPSIElement(@Nullable final Object element) { // E.g is used by Project View's DataProvider @@ -305,20 +317,23 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id return content == null ? null : (MvcProjectViewPane)content.getDisposer(); } + @Override public void selectElement(PsiElement element) { PsiFileSystemItem psiFile; - - if (!(element instanceof PsiFileSystemItem)) { - psiFile = element.getContainingFile(); + if (element instanceof PsiFileSystemItem) { + psiFile = (PsiFileSystemItem)element; } else { - psiFile = (PsiFileSystemItem)element; + psiFile = element.getContainingFile(); + if (psiFile == null) { + return; + } } - if (psiFile == null) return; - VirtualFile virtualFile = psiFile.getVirtualFile(); - if (virtualFile == null) return; + if (virtualFile == null) { + return; + } selectFile(virtualFile, false); @@ -337,10 +352,12 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id } } + @Override public PsiDirectory[] getDirectories() { return getSelectedDirectories(); } + @Override public PsiDirectory getOrChooseDirectory() { return DirectoryChooserUtil.getOrChooseDirectory(this); } @@ -360,7 +377,7 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id return null; } - final Module module = ModuleUtil.findModuleForFile(file, project); + final Module module = ModuleUtilCore.findModuleForFile(file, project); if (module == null || !framework.hasSupport(module)) { return null; } @@ -386,7 +403,7 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id if (descriptor instanceof AbstractFolderNode) { final AbstractFolderNode folderNode = (AbstractFolderNode)descriptor; final VirtualFile dir = folderNode.getVirtualFile(); - if (dir != null && VfsUtil.isAncestor(dir, file, false)) { + if (dir != null && VfsUtilCore.isAncestor(dir, file, false)) { cur = folderNode; result.add(folderNode); if (dir.equals(file)) { @@ -506,6 +523,7 @@ public class MvcProjectViewPane extends AbstractProjectViewPSIPane implements Id return myViewState.hideEmptyMiddlePackages; } + @Override public void setSelected(AnActionEvent event, boolean flag) { myViewState.hideEmptyMiddlePackages = flag; TreeUtil.collapseAll(myTree, 1); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java index d0b59c48b873..22c7a1871954 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestGenerator.java @@ -47,6 +47,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; /** * @author Maxim.Medvedev @@ -138,14 +140,15 @@ public class GroovyTestGenerator implements TestGenerator { Collection<MemberInfo> methods, boolean generateBefore, boolean generateAfter) throws IncorrectOperationException { + final HashSet<String> existingNames = new HashSet<String>(); if (generateBefore) { - generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null); + generateMethod(TestIntegrationUtils.MethodKind.SET_UP, descriptor, targetClass, editor, null, existingNames); } if (generateAfter) { - generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null); + generateMethod(TestIntegrationUtils.MethodKind.TEAR_DOWN, descriptor, targetClass, editor, null, existingNames); } for (MemberInfo m : methods) { - generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName()); + generateMethod(TestIntegrationUtils.MethodKind.TEST, descriptor, targetClass, editor, m.getMember().getName(), existingNames); } } @@ -163,10 +166,10 @@ public class GroovyTestGenerator implements TestGenerator { TestFramework descriptor, PsiClass targetClass, Editor editor, - @Nullable String name) { + @Nullable String name, Set<String> existingNames) { GroovyPsiElementFactory f = GroovyPsiElementFactory.getInstance(targetClass.getProject()); PsiMethod method = (PsiMethod)targetClass.add(f.createMethod("dummy", PsiType.VOID)); PsiDocumentManager.getInstance(targetClass.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()); - TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true); + TestIntegrationUtils.runTestMethodTemplate(methodKind, descriptor, editor, targetClass, method, name, true, existingNames); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index be51fc91c38a..4b40ce77fa65 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -92,7 +92,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> { private final HgCheckinEnvironment checkinEnvironment; private final HgAnnotationProvider annotationProvider; private final HgUpdateEnvironment updateEnvironment; - private final HgCachingCommitedChangesProvider commitedChangesProvider; + private final HgCachingCommittedChangesProvider committedChangesProvider; private MessageBusConnection messageBusConnection; @NotNull private final HgGlobalSettings globalSettings; @NotNull private final HgProjectSettings projectSettings; @@ -127,7 +127,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> { checkinEnvironment = new HgCheckinEnvironment(project); annotationProvider = new HgAnnotationProvider(project); updateEnvironment = new HgUpdateEnvironment(project); - commitedChangesProvider = new HgCachingCommitedChangesProvider(project, this); + committedChangesProvider = new HgCachingCommittedChangesProvider(project, this); myMergeProvider = new HgMergeProvider(myProject); myCommitAndPushExecutor = new HgCommitAndPushExecutor(checkinEnvironment); } @@ -205,7 +205,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> { @Override public CommittedChangesProvider getCommittedChangesProvider() { - return commitedChangesProvider; + return committedChangesProvider; } @Override diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgLogCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgLogCommand.java index 740603de504a..2faf8760f206 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgLogCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgLogCommand.java @@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.HgRevisionNumber; +import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandException; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; @@ -36,12 +37,18 @@ import java.util.*; public class HgLogCommand { private static final Logger LOG = Logger.getInstance(HgLogCommand.class.getName()); - private static final String[] SHORT_TEMPLATE_ITEMS = {"{rev}", "{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}"}; private static final String[] LONG_TEMPLATE_ITEMS = {"{rev}", "{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}", "{file_adds}", "{file_mods}", - "{file_dels}", "{file_copies}"}; + "{file_dels}", "{join(file_copies,'" + HgChangesetUtil.FILE_SEPARATOR + "')}"}; + /** + * The reason of existing 2 different templates for bash and others explained in + * {@link org.zmlx.hg4idea.provider.HgCachingCommittedChangesProvider.HgLogArgsBuilder#getLogArgs()} + */ + private static final String[] LONG_TEMPLATE_FOR_BASH = + {"{rev}", "{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}", "{file_adds}", "{file_mods}", + "{file_dels}", "{\"join(file_copies,'" + HgChangesetUtil.FILE_SEPARATOR + "')\"}"}; private static final int REVISION_INDEX = 0; private static final int CHANGESET_INDEX = 1; @@ -96,7 +103,15 @@ public class HgLogCommand { return Collections.emptyList(); } - String template = HgChangesetUtil.makeTemplate(includeFiles ? LONG_TEMPLATE_ITEMS : SHORT_TEMPLATE_ITEMS); + String template; + HgVcs vcs = HgVcs.getInstance(myProject); + if (vcs != null && vcs.getGlobalSettings().isRunViaBash() && includeFiles) { + template = HgChangesetUtil.makeTemplate(LONG_TEMPLATE_FOR_BASH); + } + else { + template = HgChangesetUtil.makeTemplate(includeFiles ? LONG_TEMPLATE_ITEMS : SHORT_TEMPLATE_ITEMS); + } + int expectedItemCount = includeFiles ? LONG_TEMPLATE_ITEMS.length : SHORT_TEMPLATE_ITEMS.length; FilePath originalFileName = HgUtil.getOriginalFileName(hgFile.toFilePath(), ChangeListManager.getInstance(myProject)); @@ -118,7 +133,7 @@ public class HgLogCommand { try { String[] attributes = line.split(HgChangesetUtil.ITEM_SEPARATOR); // At least in the case of the long template, it's OK that we don't have everything...for example, if there were no - // deleted or copied files, then we won't get any attribtes for them... + // deleted or copied files, then we won't get any attributes for them... int numAttributes = attributes.length; if (!includeFiles && (numAttributes != expectedItemCount)) { LOG.debug("Wrong format. Skipping line " + line); @@ -244,58 +259,20 @@ public class HgLogCommand { } @NotNull - private static Map<String, String> parseCopiesFileList(@Nullable String fileListString) { + public static Map<String, String> parseCopiesFileList(@Nullable String fileListString) { if (StringUtil.isEmpty(fileListString)) { return Collections.emptyMap(); } - else { - Map<String, String> copies = new HashMap<String, String>(); - assert fileListString != null; // checked via StringUtil - //hg copied files output looks like: "target1 (source1)target2 (source2)target3 .... (target_n)" - //so we should split i-1 source from i target. - // If some sources or targets contatins '(' we suppose that it has Regular Bracket sequence and perform appropriate string parsing. - //if it fails just return. (to avoid ArrayIndexOutOfBoundsException) - String[] filesList = fileListString.split("\\s"); - String target = filesList[0]; - - for (int i = 1; i < filesList.length; ++i) { - String source = filesList[i]; - int afterRightBraceIndex = findRightBracePosition(source); - if (afterRightBraceIndex == -1) { - break; - } - copies.put(source.substring(0, afterRightBraceIndex), target); - if (afterRightBraceIndex >= source.length()) { //the last 'word' in str - break; - } - target = source.substring(afterRightBraceIndex); - } - return copies; - } - } + Map<String, String> copies = new HashMap<String, String>(); + String[] filesList = fileListString.split(HgChangesetUtil.FILE_SEPARATOR); - private static int findRightBracePosition(@NotNull String str) { - if (!str.startsWith("(")) { - LOG.info("Unexpected output during parse copied files in log command " + str); - return -1; - } - int len = str.length(); - int depth = 0; - for (int i = 0; i < len; ++i) { - char c = str.charAt(i); - switch (c) { - case '(': - depth++; - break; - case ')': - depth--; - break; - } - if (depth == 0) { - return i + 1; + for (String pairOfFiles : filesList) { + String[] files = pairOfFiles.split("\\s+\\("); + if (files.length != 2) { + LOG.error("Couldn't parse copied files: " + fileListString); } + copies.put(files[1].substring(0, files[1].length() - 1), files[0]); } - LOG.info("Unexpected output during parse copied files in log command " + str); - return -1; + return copies; } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/ShellCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/ShellCommand.java index e9ca21463fd1..d41cd4d92508 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/ShellCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/ShellCommand.java @@ -43,11 +43,11 @@ public final class ShellCommand { } if (myRunViaBash) { - // run via bash -cl <hg command> => need to escape bash special symbols + // run via bash -cl <hg command> => need to escape bash special symbols but not quoted // '-l' makes bash execute as a login shell thus reading .bash_profile StringBuilder hgCommandBuilder = new StringBuilder(); for (String command : commandLine) { - hgCommandBuilder.append(escapeSpacesIfNeeded(command)); + hgCommandBuilder.append(command); //do not escape whitespaces because arguments may be quoted hgCommandBuilder.append(" "); } String hgCommand = escapeBashControlCharacters(hgCommandBuilder.toString()); @@ -72,42 +72,33 @@ public final class ShellCommand { int exitValue = processOutput.getExitCode(); out.write(processOutput.getStdout()); err.write(processOutput.getStderr()); - return new HgCommandResult(out, err, exitValue ); - } catch (IOException e) { + return new HgCommandResult(out, err, exitValue); + } + catch (IOException e) { throw new ShellCommandException(e); } } /** - * Escapes charactes in the command which will be executed via 'bash -c' - these are standard chars like \n, and some bash specials. + * Escapes characters in the command which will be executed via 'bash -c' - these are standard chars like \n, and some bash specials. + * * @param source Original string. * @return Escaped string. */ - private static String escapeBashControlCharacters(String source) { - final String controlChars = "|>$\"'&"; - final String standardChars = "\b\t\n\f\r"; - final String standardCharsLetters = "btnfr"; + private static String escapeBashControlCharacters(@NotNull String source) { + //need to control other bash control chars manually to avoid conflicts with mercurial symbols (>,',", whitespaces) + final String controlChars = "|&$"; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < source.length(); i++) { char ch = source.charAt(i); if (controlChars.indexOf(ch) > -1) { sb.append("\\").append(ch); - } else { - final int index = standardChars.indexOf(ch); - if (index > -1) { - sb.append("\\").append(standardCharsLetters.charAt(index)); - } else { - sb.append(ch); - } + } + else { + sb.append(ch); } } return sb.toString(); } - - @NotNull - private String escapeSpacesIfNeeded(@NotNull String s) { - return myRunViaBash ? s.replace(" ", "\\ ") : s; - } - } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommittedChangesProvider.java index 6d6b771e2fd5..f5d4b8654d94 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommittedChangesProvider.java @@ -50,13 +50,13 @@ import java.io.IOException; import java.text.SimpleDateFormat; import java.util.*; -public class HgCachingCommitedChangesProvider implements CachingCommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> { +public class HgCachingCommittedChangesProvider implements CachingCommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> { private final Project project; private final HgVcs myVcs; public final static int VERSION_WITH_REPOSITORY_BRANCHES = 2; - public HgCachingCommitedChangesProvider(Project project, HgVcs vcs) { + public HgCachingCommittedChangesProvider(Project project, HgVcs vcs) { this.project = project; myVcs = vcs; } @@ -214,7 +214,7 @@ public class HgCachingCommitedChangesProvider implements CachingCommittedChanges hgLogCommand.setLogFile(false); List<String> args = null; if (changeBrowserSettings != null) { - HgLogArgsBuilder argsBuilder = new HgLogArgsBuilder(changeBrowserSettings); + HgLogArgsBuilder argsBuilder = new HgLogArgsBuilder(changeBrowserSettings, myVcs.getGlobalSettings().isRunViaBash()); args = argsBuilder.getLogArgs(); if (args.isEmpty()) { maxCount = maxCount == 0 ? VcsConfiguration.getInstance(project).MAXIMUM_HISTORY_ROWS : maxCount; @@ -304,11 +304,11 @@ public class HgCachingCommitedChangesProvider implements CachingCommittedChanges settings.CHANGE_AFTER = number.asString(); settings.CHANGE_BEFORE = number.asString(); // todo implement in proper way - VirtualFile localVitrualFile = HgUtil.convertToLocalVirtualFile(file); - if (localVitrualFile == null) { + VirtualFile localVirtualFile = HgUtil.convertToLocalVirtualFile(file); + if (localVirtualFile == null) { return null; } - final FilePathImpl filePath = new FilePathImpl(localVitrualFile); + final FilePathImpl filePath = new FilePathImpl(localVirtualFile); final CommittedChangeList list = getCommittedChangesForRevision(getLocationFor(filePath), number.asString()); if (list != null) { return new Pair<CommittedChangeList, FilePath>(list, filePath); @@ -385,41 +385,49 @@ public class HgCachingCommitedChangesProvider implements CachingCommittedChanges private static class HgLogArgsBuilder { @NotNull private final ChangeBrowserSettings myBrowserSettings; + private final boolean isRunViaBash; - HgLogArgsBuilder(@NotNull ChangeBrowserSettings browserSettings) { + HgLogArgsBuilder(@NotNull ChangeBrowserSettings browserSettings, boolean runViaBash) { myBrowserSettings = browserSettings; + isRunViaBash = runViaBash; } @NotNull List<String> getLogArgs() { StringBuilder args = new StringBuilder(); - Date afterDate = myBrowserSettings.getDateAfter(); Date beforeDate = myBrowserSettings.getDateBefore(); Long afterFilter = myBrowserSettings.getChangeAfterFilter(); Long beforeFilter = myBrowserSettings.getChangeBeforeFilter(); final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - - if ((null != afterFilter) && (null != beforeFilter)) { + //if command executed via bash all mercurial internal (like date, ancestor etc. ) commands should be quoted, + // but several commands should be quoted once not each. + //f.e. bash -cl 'hg log --rev "date('> 2013')"' OR bash -cl 'hg log --rev "date('> 2013') and date('< 2014')" ' + //this complex workaround is needed because java process wrap arguments in single or double quotes, + // so this may produce conflicts with hg commands. + //If command wrapped by quotes should not escape bash control symbols inside! + String separator = isRunViaBash ? "\"" : ""; + + if ((afterFilter != null) && (beforeFilter != null)) { args.append(afterFilter).append(":").append(beforeFilter); } - else if (null != afterFilter) { + else if (afterFilter != null) { args.append("tip:").append(afterFilter); } - else if (null != beforeFilter) { - args.append("'reverse(:").append(beforeFilter).append(")'"); + else if (beforeFilter != null) { + args.append("reverse(:").append(beforeFilter).append(")"); } - if (null != afterDate) { + if (afterDate != null) { if (args.length() > 0) { args.append(" and "); } args.append("date('>").append(dateFormatter.format(afterDate)).append("')"); } - if (null != beforeDate) { + if (beforeDate != null) { if (args.length() > 0) { args.append(" and "); } @@ -430,7 +438,7 @@ public class HgCachingCommitedChangesProvider implements CachingCommittedChanges if (args.length() > 0) { List<String> logArgs = new ArrayList<String>(); logArgs.add("-r"); - logArgs.add(args.toString()); + logArgs.add(separator + args.toString() + separator); return logArgs; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java index 9118dc217fb9..db5a7135d560 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java @@ -19,15 +19,20 @@ import com.intellij.openapi.util.SystemInfo; /** * Utilities for operations involving working with a number of changesets: log, incoming, outgoing, parents, etc. + * Storage for different mercurial response separators. + * * @author Kirill Likhodedov */ public class HgChangesetUtil { public static final String CHANGESET_SEPARATOR = "\u0003"; public static final String ITEM_SEPARATOR = "\u0017"; + public static final String FILE_SEPARATOR = "\u0001"; +//FILE_SEPARATOR used for file_copies pair (by default no separator between prev source and next target) /** * Common method for hg commands which receive templates via --template option. + * * @param templateItems template items like <pre>{rev}</pre>, <pre>{node}</pre>. * @return items joined by ITEM_SEPARATOR, ended by CHANGESET_SEPARATOR, and, if needed (for Windows), surrounded with double-quotes. */ @@ -44,5 +49,4 @@ public class HgChangesetUtil { } return template.toString(); } - } diff --git a/plugins/hg4idea/testSrc/hg4idea/test/history/HgLogTest.java b/plugins/hg4idea/testSrc/hg4idea/test/history/HgLogTest.java index d6f9d7b2e7bc..4e1638e00ff1 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/history/HgLogTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/history/HgLogTest.java @@ -1,15 +1,18 @@ package hg4idea.test.history; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import hg4idea.test.HgPlatformTest; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; +import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.command.HgLogCommand; import org.zmlx.hg4idea.execution.HgCommandException; import java.util.List; +import java.util.Map; import static com.intellij.dvcs.test.Executor.cd; import static com.intellij.dvcs.test.Executor.touch; @@ -19,6 +22,14 @@ import static hg4idea.test.HgExecutor.hg; * @author Nadya Zabrodina */ public class HgLogTest extends HgPlatformTest { + private HgVcs myVcs; + + @Override + public void setUp() throws Exception { + super.setUp(); + myVcs = HgVcs.getInstance(myProject); + assert myVcs != null; + } public void testParseCopiedWithoutBraces() throws HgCommandException { parseCopied("f.txt"); @@ -28,6 +39,22 @@ public class HgLogTest extends HgPlatformTest { parseCopied("(f.txt)"); } + public void testLogCommandViaBash() throws HgCommandException { + if (SystemInfo.isWindows) { + return; + } + myVcs.getGlobalSettings().setRunViaBash(true); + parseCopied("f.txt"); + } + + public void testParseFileCopiesWithWhitespaces() { + Map<String, String> filesMap = HgLogCommand.parseCopiesFileList("/a/b c/d.txt (a/b a/d.txt)\u0001/a/b c/(d).txt (/a/b c/(f).txt)"); + assertTrue(filesMap.containsKey("a/b a/d.txt")); + assertTrue(filesMap.containsKey("/a/b c/(f).txt")); + assertTrue(filesMap.containsValue("/a/b c/d.txt")); + assertTrue(filesMap.containsValue("/a/b c/(d).txt")); + } + private void parseCopied(@NotNull String sourceFileName) throws HgCommandException { cd(myRepository); String copiedFileName = "copy".concat(sourceFileName); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 071429050545..cdd5ad02b84f 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -61,6 +61,7 @@ import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; @@ -71,6 +72,7 @@ import com.intellij.rt.execution.junit.JUnitStarter; import com.intellij.util.Function; import com.intellij.util.PathUtil; import jetbrains.buildServer.messages.serviceMessages.ServiceMessageTypes; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.model.serialization.PathMacroUtil; @@ -83,7 +85,7 @@ public abstract class TestObject implements JavaCommandLine { protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject"); private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message"); - private static final String JUNIT_TEST_FRAMEWORK_NAME = "JUnit"; + @NonNls private static final String JUNIT_TEST_FRAMEWORK_NAME = "JUnit"; protected JavaParameters myJavaParameters; private final Project myProject; @@ -230,7 +232,7 @@ public abstract class TestObject implements JavaCommandLine { myListenersFile = FileUtil.createTempFile("junit_listeners_", ""); myListenersFile.deleteOnExit(); myJavaParameters.getProgramParametersList().add("@@" + myListenersFile.getPath()); - FileUtil.writeToFile(myListenersFile, buf.toString().getBytes()); + FileUtil.writeToFile(myListenersFile, buf.toString().getBytes(CharsetToolkit.UTF8_CHARSET)); } catch (IOException e) { LOG.error(e); @@ -416,17 +418,17 @@ public abstract class TestObject implements JavaCommandLine { private boolean forkPerModule() { final String workingDirectory = myConfiguration.getWorkingDirectory(); - return JUnitConfiguration.TEST_PACKAGE.equals(myConfiguration.getPersistentData().TEST_OBJECT) && - myConfiguration.getPersistentData().getScope() != TestSearchScope.SINGLE_MODULE && + return JUnitConfiguration.TEST_PACKAGE.equals(myConfiguration.getPersistentData().TEST_OBJECT) && + myConfiguration.getPersistentData().getScope() != TestSearchScope.SINGLE_MODULE && ("$" + PathMacroUtil.MODULE_DIR_MACRO_NAME + "$").equals(workingDirectory); } - + private void appendForkInfo(Executor executor) throws ExecutionException { final String forkMode = myConfiguration.getForkMode(); if (Comparing.strEqual(forkMode, "none")) { final String workingDirectory = myConfiguration.getWorkingDirectory(); - if (!JUnitConfiguration.TEST_PACKAGE.equals(myConfiguration.getPersistentData().TEST_OBJECT) || - myConfiguration.getPersistentData().getScope() == TestSearchScope.SINGLE_MODULE || + if (!JUnitConfiguration.TEST_PACKAGE.equals(myConfiguration.getPersistentData().TEST_OBJECT) || + myConfiguration.getPersistentData().getScope() == TestSearchScope.SINGLE_MODULE || !("$" + PathMacroUtil.MODULE_DIR_MACRO_NAME + "$").equals(workingDirectory)) { return; } @@ -445,7 +447,7 @@ public abstract class TestObject implements JavaCommandLine { try { final File tempFile = FileUtil.createTempFile("command.line", "", true); - final PrintWriter writer = new PrintWriter(tempFile, "UTF-8"); + final PrintWriter writer = new PrintWriter(tempFile, CharsetToolkit.UTF8); try { writer.println(((JavaSdkType)jdk.getSdkType()).getVMExecutablePath(jdk)); for (String vmParameter : javaParameters.getVMParametersList().getList()) { @@ -457,7 +459,7 @@ public abstract class TestObject implements JavaCommandLine { finally { writer.close(); } - + myJavaParameters.getProgramParametersList().add("@@@" + forkMode + ',' + tempFile.getAbsolutePath()); } catch (Exception e) { @@ -476,7 +478,7 @@ public abstract class TestObject implements JavaCommandLine { } final Map<String, List<String>> perModule = forkPerModule() ? new TreeMap<String, List<String>>() : null; - final PrintWriter writer = new PrintWriter(myTempFile, "UTF-8"); + final PrintWriter writer = new PrintWriter(myTempFile, CharsetToolkit.UTF8); try { writer.println(packageName); final List<String> testNames = new ArrayList<String>(); @@ -519,7 +521,7 @@ public abstract class TestObject implements JavaCommandLine { } if (perModule != null && perModule.size() > 1) { - final PrintWriter wWriter = new PrintWriter(myWorkingDirsFile, "UTF-8"); + final PrintWriter wWriter = new PrintWriter(myWorkingDirsFile, CharsetToolkit.UTF8); try { wWriter.println(packageName); for (String workingDir : perModule.keySet()) { diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java b/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java index f91cedd49688..b6c1257a4b6c 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/TestsPacketsReceiver.java @@ -42,6 +42,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.rt.execution.junit.segments.PoolOfDelimiters; import com.intellij.rt.execution.junit.states.PoolOfTestStates; import com.intellij.util.containers.HashMap; +import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,10 +52,9 @@ import java.util.Map; import java.util.Set; public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { - - public static final Map<Integer, StateChanger> STATE_CLASSES = new HashMap<Integer, StateChanger>(); + private static final TIntObjectHashMap<StateChanger> STATE_CLASSES = new TIntObjectHashMap<StateChanger>(); private Map<String, TestProxy> myKnownDynamicParents; - private TestProxy myUnboundOutput; + private final TestProxy myUnboundOutput; static { mapClass(PoolOfTestStates.RUNNING_INDEX, new RunningStateSetter()); @@ -66,9 +66,9 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { mapClass(PoolOfTestStates.COMPARISON_FAILURE, new StateReader(ComparisonFailureState.class)); } - public static void mapClass(final int magnitude, final StateChanger factory) { + public static void mapClass(final int magnitude, @NotNull StateChanger factory) { factory.setMagnitude(magnitude); - STATE_CLASSES.put(new Integer(magnitude), factory); + STATE_CLASSES.put(magnitude, factory); } private final InputObjectRegistry myObjectRegistry; @@ -86,6 +86,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { Disposer.register(consoleView, this); } + @Override public void processPacket(final String packet) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -162,6 +163,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { setClassName(parentClass); } + @Override public void readFrom(ObjectReader reader) { } }); @@ -180,7 +182,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { } final int state = reader.readInt(); - final StateChanger stateChanger = STATE_CLASSES.get(new Integer(state)); + final StateChanger stateChanger = STATE_CLASSES.get(state); stateChanger.changeStateOf(testProxy, reader); synchronized (myCurrentTests) { if (stateChanger instanceof RunningStateSetter) { @@ -217,6 +219,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { return myModel; } + @Override public void dispose() { myModel = null; } @@ -252,7 +255,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { } } - private static abstract class StateChanger { + private abstract static class StateChanger { static final Logger LOG = Logger.getInstance("#" + StateChanger.class.getName()); abstract void changeStateOf(TestProxy testProxy, ObjectReader reader); @@ -283,6 +286,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { } private static class RunningStateSetter extends StateChanger { + @Override public void changeStateOf(final TestProxy testProxy, final ObjectReader reader) { testProxy.setState(TestState.RUNNING_STATE); TestProxy parent = testProxy.getParent(); @@ -304,6 +308,7 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { myStateClass = stateClass; } + @Override public void changeStateOf(final TestProxy testProxy, final ObjectReader reader) { final ReadableState state; try { @@ -319,12 +324,14 @@ public class TestsPacketsReceiver implements OutputPacketProcessor, Disposable { complete(testProxy); } + @Override public void setMagnitude(final int magnitude) { myInstanceMagnitude = magnitude; } } private static class TestCompleter extends StateChanger { + @Override public void changeStateOf(final TestProxy testProxy, final ObjectReader reader) { TestState state = testProxy.getState(); if (!testProxy.getState().isFinal()) { diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java index 1dc84b944f5b..5e087258b3f4 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java @@ -24,6 +24,7 @@ import com.intellij.tasks.TaskManager; import com.intellij.tasks.TaskRepository; import com.intellij.tasks.TaskState; import com.intellij.tasks.impl.TaskManagerImpl; +import com.intellij.tasks.impl.TaskUtil; import com.intellij.ui.components.JBCheckBox; import javax.swing.*; @@ -45,7 +46,7 @@ public class CloseTaskDialog extends DialogWrapper { super(project, false); setTitle("Close Task"); - myTaskLabel.setText(task.getSummary()); + myTaskLabel.setText(TaskUtil.getTrimmedSummary(task)); myTaskLabel.setIcon(task.getIcon()); TaskRepository repository = task.getRepository(); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.form b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.form index bb2cf0d68e45..a81ab2aaa098 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.form +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.form @@ -3,7 +3,7 @@ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="579" height="400"/> + <xy x="20" y="20" width="538" height="293"/> </constraints> <properties/> <border type="none"/> @@ -19,7 +19,7 @@ <grid id="7efb3" binding="myServersPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> <constraints> <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="0" height="100"/> + <preferred-size width="0" height="50"/> </grid> </constraints> <properties/> @@ -32,7 +32,26 @@ </constraints> <properties/> <border type="none"/> - <children/> + <children> + <grid id="602e0" binding="myEmptyPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> + <constraints> + <card name="Card1"/> + </constraints> + <properties/> + <border type="empty"> + <size top="100" left="220" bottom="100" right="220"/> + </border> + <children> + <component id="76503" class="com.intellij.ui.components.JBLabel"> + <constraints border-constraint="Center"/> + <properties> + <horizontalAlignment value="0"/> + <text value="No server selected"/> + </properties> + </component> + </children> + </grid> + </children> </grid> <component id="4840c" class="com.intellij.openapi.ui.Splitter" binding="mySplitter"> <constraints> diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java index 7f94c639f730..1b5ad857daa9 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskRepositoriesConfigurable.java @@ -44,6 +44,7 @@ import java.util.Set; @SuppressWarnings("unchecked") public class TaskRepositoriesConfigurable extends BaseConfigurable implements Configurable.NoScroll { + private static final String EMPTY_PANEL = "empty.panel"; private JPanel myPanel; private JPanel myServersPanel; private final JBList myRepositoriesList; @@ -52,6 +53,7 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co private JPanel myRepositoryEditor; private JBLabel myServersLabel; private Splitter mySplitter; + private JPanel myEmptyPanel; private final List<TaskRepository> myRepositories = new ArrayList<TaskRepository>(); private final List<TaskRepositoryEditor> myEditors = new ArrayList<TaskRepositoryEditor>(); @@ -237,6 +239,8 @@ public class TaskRepositoriesConfigurable extends BaseConfigurable implements Co public void reset() { myRepoNames.clear(); myRepositoryEditor.removeAll(); + myRepositoryEditor.add(myEmptyPanel, EMPTY_PANEL); +// ((CardLayout)myRepositoryEditor.getLayout()).show(myRepositoryEditor, ); myRepositories.clear(); CollectionListModel listModel = new CollectionListModel(new ArrayList()); diff --git a/plugins/tasks/tasks-time-tracking/src/META-INF/plugin.xml b/plugins/tasks/tasks-time-tracking/src/META-INF/plugin.xml deleted file mode 100644 index d0b4664d1072..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/META-INF/plugin.xml +++ /dev/null @@ -1,26 +0,0 @@ -<idea-plugin version="2"> - <id>com.intellij.tasks.timeTracking</id> - <name>Time Tracking</name> - <description>Enables time tracking for "Task Management" plugin</description> - <vendor>JetBrains</vendor> - <version>1.0</version> - - <depends>com.intellij.tasks</depends> - - <project-components> - <component> - <implementation-class>com.intellij.tasks.timeTracking.TimeTrackingManager</implementation-class> - </component> - </project-components> - - <extensions defaultExtensionNs="com.intellij"> - <projectConfigurable instance="com.intellij.tasks.timeTracking.TimeTrackingConfigurable" displayName="Time Tracking" - id="tasks.timeTracking" - nonDefaultProject="true" - parentId="tasks"/> - - <toolWindow id="Time Tracking" anchor="right" secondary="false" icon="TasksIcons.Clock" - factoryClass="com.intellij.tasks.timeTracking.TasksToolWindowFactory" - conditionClass="com.intellij.tasks.timeTracking.TasksToolWindowFactory"/> - </extensions> -</idea-plugin> diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.form b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.form deleted file mode 100644 index 2470a2f7ef4f..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.form +++ /dev/null @@ -1,130 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.tasks.timeTracking.SendTimeTrackingInformationDialog"> - <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <xy x="20" y="20" width="721" height="328"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <component id="c5275" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Issue:"/> - </properties> - </component> - <component id="59138" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Comment:"/> - <toolTipText value=""/> - </properties> - </component> - <component id="225af" class="javax.swing.JLabel" binding="myTaskNameLabel"> - <constraints> - <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Label"/> - </properties> - </component> - <scrollpane id="f2f7d" class="com.intellij.ui.components.JBScrollPane"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <component id="e531f" class="javax.swing.JTextArea" binding="myCommentTextArea"> - <constraints/> - <properties/> - </component> - </children> - </scrollpane> - <grid id="50cf9" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="5" left="0" bottom="5" right="0"/> - <constraints> - <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="true"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <component id="45822" class="javax.swing.JRadioButton" binding="myFromPreviousPostRadioButton" default-binding="true"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="From &previous post:"/> - </properties> - </component> - <component id="a4c4" class="javax.swing.JRadioButton" binding="myCustomRadioButton" default-binding="true"> - <constraints> - <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Custo&m:"/> - </properties> - </component> - <component id="89994" class="javax.swing.JTextField" binding="myFromPreviousPostTextField"> - <constraints> - <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties> - <editable value="false"/> - </properties> - </component> - <component id="c9593" class="javax.swing.JTextField" binding="myCustomTextField"> - <constraints> - <grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties> - <text value="0d 0h 0m"/> - </properties> - </component> - <component id="65cc2" class="javax.swing.JRadioButton" binding="myTotallyRadioButton" default-binding="true"> - <constraints> - <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Totall&y:"/> - </properties> - </component> - <component id="8f5d7" class="javax.swing.JTextField" binding="myTotallyTextField"> - <constraints> - <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="150" height="-1"/> - </grid> - </constraints> - <properties> - <editable value="false"/> - </properties> - </component> - <component id="bbd54" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Time Spent:"/> - </properties> - </component> - </children> - </grid> - </children> - </grid> - <buttonGroups> - <group name="myGroup1"> - <member id="45822"/> - <member id="65cc2"/> - <member id="a4c4"/> - </group> - </buttonGroups> -</form> diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.java b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.java deleted file mode 100644 index c0f2cc0a8965..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/SendTimeTrackingInformationDialog.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.timeTracking; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.ValidationInfo; -import com.intellij.tasks.LocalTask; -import com.intellij.tasks.TaskRepository; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * User: evgeny.zakrevsky - * Date: 12/26/12 - */ -public class SendTimeTrackingInformationDialog extends DialogWrapper { - private final static Logger LOG = Logger.getInstance("#com.intellij.tasks.timeTracking.TasksToolWindowPanel"); - public static final Pattern PATTERN = Pattern.compile("([0-9]+)d ([0-9]+)h ([0-9]+)m"); - - @Nullable private final Project myProject; - private final LocalTask myTask; - private JRadioButton myFromPreviousPostRadioButton; - private JRadioButton myTotallyRadioButton; - private JRadioButton myCustomRadioButton; - private JTextField myFromPreviousPostTextField; - private JTextField myTotallyTextField; - private JTextField myCustomTextField; - private JTextArea myCommentTextArea; - private JPanel myPanel; - private JLabel myTaskNameLabel; - - protected SendTimeTrackingInformationDialog(@Nullable final Project project, final LocalTask localTask) { - super(project); - myProject = project; - myTask = localTask; - setTitle("Time Tracking"); - - myTaskNameLabel.setText(myTask.getPresentableName()); - myFromPreviousPostRadioButton.setSelected(true); - if (myTask.getLastPost() == null) { - myFromPreviousPostRadioButton.setVisible(false); - myFromPreviousPostTextField.setVisible(false); - myTotallyRadioButton.setSelected(true); - } - myFromPreviousPostTextField.setText(formatDuration(myTask.getTimeSpentFromLastPost())); - myTotallyTextField.setText(formatDuration(myTask.getTotalTimeSpent())); - - init(); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - return myPanel; - } - - private static String formatDuration(final long milliseconds) { - final int second = 1000; - final int minute = 60 * second; - final int hour = 60 * minute; - final int day = 24 * hour; - - final int days = (int)(milliseconds / day); - final int hours = (int)(milliseconds % day / hour); - final int minutes = (int)(milliseconds % hour / minute); - - String daysString = days + "d "; - String hoursString = hours + "h "; - String minutesString = minutes + "m"; - - return daysString + hoursString + minutesString; - } - - @Override - protected void doOKAction() { - String timeSpentText = myFromPreviousPostRadioButton.isSelected() ? myFromPreviousPostTextField.getText() - : myTotallyRadioButton.isSelected() ? myTotallyTextField.getText() : myCustomTextField.getText(); - final Matcher matcher = PATTERN.matcher(timeSpentText); - if (matcher.matches()) { - final int timeSpent = Integer.valueOf(matcher.group(1)) * 24 * 60 + Integer.valueOf(matcher.group(2)) * 60 + Integer.valueOf( - matcher.group(3)); - - final TaskRepository repository = myTask.getRepository(); - if (repository != null && - repository.isSupported(TaskRepository.TIME_MANAGEMENT)) { - try { - repository.updateTimeSpent(myTask, timeSpentText, myCommentTextArea.getText()); - myTask.setLastPost(new Date()); - } - catch (Exception e1) { - Messages - .showErrorDialog(myProject, "<html>Could not send information for " + myTask.getPresentableName() + "<br/>" + e1.getMessage(), - "Error"); - LOG.warn(e1); - } - } - } - - - super.doOKAction(); - } - - @Nullable - @Override - protected ValidationInfo doValidate() { - String timeSpentText = myFromPreviousPostRadioButton.isSelected() ? myFromPreviousPostTextField.getText() - : myTotallyRadioButton.isSelected() ? myTotallyTextField.getText() : myCustomTextField.getText(); - if (!PATTERN.matcher(timeSpentText).matches()) return new ValidationInfo("Time Spent has broken format"); - return null; - } - - @Nullable - @Override - protected String getDimensionServiceKey() { - return "com.intellij.tasks.timeTracking.TasksToolWindowPanel"; - } -} diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowFactory.java b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowFactory.java deleted file mode 100644 index fd1593fc94b2..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.intellij.tasks.timeTracking; - -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowAnchor; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; -import com.intellij.ui.content.ContentManager; - -/** - * User: evgeny.zakrevsky - * Date: 11/8/12 - */ -public class TasksToolWindowFactory implements ToolWindowFactory, Condition<Project>, DumbAware { - - @Override - public boolean value(final Project project) { - return TimeTrackingManager.getInstance(project).isTimeTrackingToolWindowAvailable(); - } - - @Override - public void createToolWindowContent(final Project project, final ToolWindow toolWindow) { - final ContentManager contentManager = toolWindow.getContentManager(); - final Content content = ContentFactory.SERVICE.getInstance(). - createContent(new TasksToolWindowPanel(project, toolWindow.getAnchor() == ToolWindowAnchor.LEFT || - toolWindow.getAnchor() == ToolWindowAnchor.RIGHT), null, false); - contentManager.addContent(content); - } -} diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowPanel.java b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowPanel.java deleted file mode 100644 index 9e28eec7fe34..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TasksToolWindowPanel.java +++ /dev/null @@ -1,363 +0,0 @@ -package com.intellij.tasks.timeTracking; - -import com.intellij.icons.AllIcons; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.SimpleToolWindowPanel; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.IconLoader; -import com.intellij.tasks.*; -import com.intellij.tasks.actions.GotoTaskAction; -import com.intellij.tasks.actions.SwitchTaskAction; -import com.intellij.ui.LayeredIcon; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.ui.SimpleColoredComponent; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.ui.table.TableView; -import com.intellij.util.IconUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.text.DateFormatUtil; -import com.intellij.util.ui.ColumnInfo; -import com.intellij.util.ui.ListTableModel; -import com.intellij.util.ui.UIUtil; -import icons.TasksIcons; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.table.TableCellRenderer; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Comparator; - -/** - * User: evgeny.zakrevsky - * Date: 11/8/12 - */ -public class TasksToolWindowPanel extends SimpleToolWindowPanel implements Disposable { - - private final ListTableModel<LocalTask> myTableModel; - private final TimeTrackingManager myTimeTrackingManager; - private final Project myProject; - private Timer myTimer; - private final TableView<LocalTask> myTable; - private final TaskManager myTaskManager; - - public TasksToolWindowPanel(final Project project, final boolean vertical) { - super(vertical); - myProject = project; - myTimeTrackingManager = TimeTrackingManager.getInstance(project); - myTaskManager = TaskManager.getManager(project); - - myTable = new TableView<LocalTask>(createListModel()); - myTableModel = myTable.getListTableModel(); - updateTable(); - - setContent(ScrollPaneFactory.createScrollPane(myTable, true)); - setToolbar(createToolbar()); - - myTaskManager.addTaskListener(new TaskListenerAdapter() { - @Override - public void taskDeactivated(final LocalTask task) { - myTable.repaint(); - } - - @Override - public void taskActivated(final LocalTask task) { - myTable.repaint(); - } - - @Override - public void taskAdded(final LocalTask task) { - updateTable(); - } - - @Override - public void taskRemoved(final LocalTask task) { - updateTable(); - } - }); - - myTimer = new Timer(TimeTrackingManager.TIME_TRACKING_TIME_UNIT, new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - myTable.repaint(); - } - }); - myTimer.start(); - } - - private static SimpleTextAttributes getAttributes(final boolean isClosed, final boolean isActive, final boolean isSelected) { - return new SimpleTextAttributes(isActive ? SimpleTextAttributes.STYLE_BOLD : SimpleTextAttributes.STYLE_PLAIN, - isSelected - ? UIUtil.getTableSelectionForeground() - : isClosed && !isActive ? UIUtil.getLabelDisabledForeground() : UIUtil.getTableForeground()); - } - - private static String formatDuration(final long milliseconds) { - final int second = 1000; - final int minute = 60 * second; - final int hour = 60 * minute; - final int day = 24 * hour; - final int days = (int)milliseconds / day; - String daysString = days != 0 ? days + "d " : ""; - - return daysString + String.format("%d:%02d:%02d", milliseconds % day / hour, milliseconds % hour / minute, - milliseconds % minute / second); - } - - private JComponent createToolbar() { - DefaultActionGroup group = new DefaultActionGroup(); - final AnAction action = ActionManager.getInstance().getAction(GotoTaskAction.ID); - assert action instanceof GotoTaskAction; - final GotoTaskAction gotoTaskAction = (GotoTaskAction)action; - group.add(gotoTaskAction); - group.add(new AnAction("Remove Task", "Remove Task", IconUtil.getRemoveIcon()) { - @Override - public void actionPerformed(final AnActionEvent e) { - for (LocalTask localTask : myTable.getSelectedObjects()) { - SwitchTaskAction.removeTask(myProject, localTask, myTaskManager); - } - } - }); - group.add(new ToggleAction("Show closed tasks", "Show closed tasks", AllIcons.Actions.Checked) { - @Override - public boolean isSelected(final AnActionEvent e) { - return myTimeTrackingManager.getState().showClosedTasks; - } - - @Override - public void setSelected(final AnActionEvent e, final boolean state) { - myTimeTrackingManager.getState().showClosedTasks = state; - updateTable(); - } - }); - group.add(new ModeToggleAction()); - group.add(new StartStopAction()); - - if (timeManagementExist()) { - group.add(new AnAction("Post work item to bugtracker", "Post work item to bugtracker", AllIcons.Actions.Export) { - @Override - public void actionPerformed(final AnActionEvent e) { - final LocalTask localTask = myTable.getSelectedObject(); - if (localTask == null) return; - new SendTimeTrackingInformationDialog(myProject, localTask).show(); - } - - @Override - public void update(final AnActionEvent e) { - final LocalTask localTask = myTable.getSelectedObject(); - if (localTask == null) { - e.getPresentation().setEnabled(false); - } - else { - final TaskRepository repository = localTask.getRepository(); - e.getPresentation().setEnabled(repository != null && repository.isSupported(TaskRepository.TIME_MANAGEMENT)); - } - } - }); - - group.add(new ToggleAction("Show time spent from last post of work item", "Show time spent from last post of work item", - TasksIcons.Clock) { - @Override - public boolean isSelected(final AnActionEvent e) { - return myTimeTrackingManager.getState().showSpentTimeFromLastPost; - } - - @Override - public void setSelected(final AnActionEvent e, final boolean state) { - myTimeTrackingManager.getState().showSpentTimeFromLastPost = state; - myTable.repaint(); - } - }); - } - final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, myVertical); - return actionToolBar.getComponent(); - } - - private void updateTable() { - myTableModel.setItems(ContainerUtil.filter(myTaskManager.getLocalTasks(), - new Condition<LocalTask>() { - @Override - public boolean value(final LocalTask task) { - return task.isActive() || - (task.getTotalTimeSpent() != 0 && - (myTimeTrackingManager.getState().showClosedTasks || - !myTaskManager.isLocallyClosed(task))); - } - })); - } - - private ListTableModel<LocalTask> createListModel() { - final ColumnInfo<LocalTask, String> task = new ColumnInfo<LocalTask, String>("Task") { - - @Nullable - @Override - public String valueOf(final LocalTask task) { - return task.getPresentableName(); - } - - @Nullable - @Override - public TableCellRenderer getRenderer(final LocalTask task) { - return new TableCellRenderer() { - @Override - public Component getTableCellRendererComponent(final JTable table, - final Object value, - final boolean isSelected, - final boolean hasFocus, - final int row, - final int column) { - JPanel panel = new JPanel(new BorderLayout()); - panel.setBackground(UIUtil.getTableBackground(isSelected)); - final SimpleColoredComponent component = new SimpleColoredComponent(); - final boolean isClosed = task.isClosed() || myTaskManager.isLocallyClosed(task); - final boolean isActive = task.isActive(); - final boolean isRunning = myTimeTrackingManager.getState().autoMode ? isActive : isActive && task.isRunning(); - component.append((String)value, getAttributes(isClosed, isActive, isSelected)); - component.setIcon(isRunning - ? LayeredIcon.create(task.getIcon(), AllIcons.Nodes.RunnableMark) - : isClosed && !isActive ? IconLoader.getTransparentIcon(task.getIcon()) : task.getIcon()); - component.setOpaque(false); - panel.add(component, BorderLayout.CENTER); - panel.setOpaque(true); - return panel; - } - }; - } - - @Nullable - @Override - public Comparator<LocalTask> getComparator() { - return new Comparator<LocalTask>() { - public int compare(LocalTask o1, LocalTask o2) { - int i = Comparing.compare(o2.getUpdated(), o1.getUpdated()); - return i == 0 ? Comparing.compare(o2.getCreated(), o1.getCreated()) : i; - } - }; - } - }; - - final ColumnInfo<LocalTask, String> spentTime = new ColumnInfo<LocalTask, String>("Time Spent") { - @Nullable - @Override - public String valueOf(final LocalTask task) { - long timeSpent = - myTimeTrackingManager.getState().showSpentTimeFromLastPost ? task.getTimeSpentFromLastPost() : task.getTotalTimeSpent(); - if (task.isActive()) { - return formatDuration(timeSpent); - } - return DateFormatUtil.formatDuration(timeSpent); - } - - @Nullable - @Override - public TableCellRenderer getRenderer(final LocalTask task) { - return new TableCellRenderer() { - @Override - public Component getTableCellRendererComponent(final JTable table, - final Object value, - final boolean isSelected, - final boolean hasFocus, - final int row, - final int column) { - JPanel panel = new JPanel(new BorderLayout()); - panel.setBackground(UIUtil.getTableBackground(isSelected)); - final SimpleColoredComponent component = new SimpleColoredComponent(); - final boolean isClosed = task.isClosed() || myTaskManager.isLocallyClosed(task); - final boolean isActive = task.isActive(); - component.append((String)value, getAttributes(isClosed, isActive, isSelected)); - component.setOpaque(false); - panel.add(component, BorderLayout.CENTER); - panel.setOpaque(true); - return panel; - } - }; - } - - @Nullable - @Override - public Comparator<LocalTask> getComparator() { - return new Comparator<LocalTask>() { - @Override - public int compare(final LocalTask o1, final LocalTask o2) { - final long timeSpent1 = - myTimeTrackingManager.getState().showSpentTimeFromLastPost ? o1.getTimeSpentFromLastPost() : o1.getTotalTimeSpent(); - final long timeSpent2 = - myTimeTrackingManager.getState().showSpentTimeFromLastPost ? o2.getTimeSpentFromLastPost() : o2.getTotalTimeSpent(); - return Comparing.compare(timeSpent1, timeSpent2); - } - }; - } - }; - - return new ListTableModel<LocalTask>((new ColumnInfo[]{task, spentTime})); - } - - private boolean timeManagementExist() { - for (TaskRepository repository : myTaskManager.getAllRepositories()) { - if (repository.isSupported(TaskRepository.TIME_MANAGEMENT)) { - return true; - } - } - return false; - } - - @Override - public void dispose() { - myTimer.stop(); - myTimer = null; - } - - private class StartStopAction extends AnAction { - @Override - public void update(final AnActionEvent e) { - if (myTimeTrackingManager.getState().autoMode) { - e.getPresentation().setEnabled(false); - e.getPresentation().setIcon(TasksIcons.StartTimer); - e.getPresentation().setText("Start timer for active task"); - } - else { - e.getPresentation().setEnabled(true); - if (myTaskManager.getActiveTask().isRunning()) { - e.getPresentation().setIcon(TasksIcons.StopTimer); - e.getPresentation().setText("Stop timer for active task"); - } - else { - e.getPresentation().setIcon(TasksIcons.StartTimer); - e.getPresentation().setText("Start timer for active task"); - } - } - } - - @Override - public void actionPerformed(final AnActionEvent e) { - final LocalTask activeTask = myTaskManager.getActiveTask(); - if (activeTask.isRunning()) { - activeTask.setRunning(false); - } - else { - activeTask.setRunning(true); - } - } - } - - private class ModeToggleAction extends ToggleAction { - public ModeToggleAction() { - super("Auto mode", "Automatic starting and stopping of timer", TasksIcons.AutoMode); - } - - @Override - public boolean isSelected(final AnActionEvent e) { - return myTimeTrackingManager.getState().autoMode; - } - - @Override - public void setSelected(final AnActionEvent e, final boolean state) { - myTimeTrackingManager.setAutoMode(state); - updateTable(); - } - } -} diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.form b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.form deleted file mode 100644 index 26dfc39e8f7c..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.form +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.tasks.timeTracking.TimeTrackingConfigurable"> - <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <xy x="20" y="20" width="500" height="400"/> - </constraints> - <properties/> - <border type="none"/> - <children> - <vspacer id="9d80d"> - <constraints> - <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> - </constraints> - </vspacer> - <grid id="f42" binding="myTimeTrackingSettings" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> - <margin top="0" left="0" bottom="0" right="0"/> - <constraints> - <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> - </constraints> - <properties/> - <clientProperties> - <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/> - </clientProperties> - <border type="none" title="Time Tracking settings"/> - <children> - <component id="e1b59" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="Suspend delay:"/> - </properties> - </component> - <component id="463e7" class="javax.swing.JTextField" binding="myTimeTrackingSuspendDelay"> - <constraints> - <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"> - <preferred-size width="50" height="-1"/> - </grid> - </constraints> - <properties/> - </component> - <component id="5584b" class="com.intellij.ui.components.JBLabel"> - <constraints> - <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="seconds"/> - </properties> - </component> - </children> - </grid> - <component id="c5b5" class="javax.swing.JCheckBox" binding="myEnableTimeTrackingCheckBox" default-binding="true"> - <constraints> - <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/> - </constraints> - <properties> - <text value="&Enable Time Tracking"/> - </properties> - </component> - <hspacer id="e6e8e"> - <constraints> - <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> - </constraints> - </hspacer> - </children> - </grid> -</form> diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.java b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.java deleted file mode 100644 index ba0f21bcd3d6..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingConfigurable.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.intellij.tasks.timeTracking; - -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; -import com.intellij.ui.GuiUtils; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * User: Evgeny.Zakrevsky - * Date: 11/19/12 - */ -public class TimeTrackingConfigurable implements SearchableConfigurable, Configurable.NoScroll { - private JCheckBox myEnableTimeTrackingCheckBox; - private JTextField myTimeTrackingSuspendDelay; - private JPanel myTimeTrackingSettings; - private JPanel myPanel; - private Project myProject; - - - public TimeTrackingConfigurable(Project project) { - myProject = project; - myEnableTimeTrackingCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - enableTimeTrackingPanel(); - } - }); - } - - private void enableTimeTrackingPanel() { - GuiUtils.enableChildren(myTimeTrackingSettings, myEnableTimeTrackingCheckBox.isSelected()); - } - - private TimeTrackingManager.Config getConfig() { - return TimeTrackingManager.getInstance(myProject).getState(); - } - - @Override - public void reset() { - myEnableTimeTrackingCheckBox.setSelected(getConfig().enabled); - myTimeTrackingSuspendDelay.setText(String.valueOf(getConfig().suspendDelayInSeconds)); - enableTimeTrackingPanel(); - } - - @Override - public void disposeUIResources() { - } - - - @Override - public boolean isModified() { - return myEnableTimeTrackingCheckBox.isSelected() != getConfig().enabled || - !myTimeTrackingSuspendDelay.getText().equals(String.valueOf(getConfig().suspendDelayInSeconds)); - } - - @Override - public void apply() { - boolean oldTimeTrackingEnabled = getConfig().enabled; - getConfig().enabled = myEnableTimeTrackingCheckBox.isSelected(); - if (getConfig().enabled != oldTimeTrackingEnabled) { - TimeTrackingManager.getInstance(myProject).updateTimeTrackingToolWindow(); - } - try{ - getConfig().suspendDelayInSeconds = Integer.parseInt(myTimeTrackingSuspendDelay.getText()); - } - catch (NumberFormatException ignored) { - } - } - - @NotNull - @Override - public String getId() { - return "tasks.timeTracking"; - } - - @Nullable - @Override - public Runnable enableSearch(final String option) { - return null; - } - - @Nls - @Override - public String getDisplayName() { - return "Time Tracking"; - } - - @Nullable - @Override - public String getHelpTopic() { - return null; - //return "reference.settings.project.tasks.timeTracking"; - } - - @Nullable - @Override - public JComponent createComponent() { - return myPanel; - } -} diff --git a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingManager.java b/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingManager.java deleted file mode 100644 index b78a24db5304..000000000000 --- a/plugins/tasks/tasks-time-tracking/src/com/intellij/tasks/timeTracking/TimeTrackingManager.java +++ /dev/null @@ -1,218 +0,0 @@ -package com.intellij.tasks.timeTracking; - -import com.intellij.ide.IdeEventQueue; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.wm.*; -import com.intellij.tasks.LocalTask; -import com.intellij.tasks.TaskManager; -import com.intellij.tasks.timeTracking.model.WorkItem; -import com.intellij.util.Alarm; -import com.intellij.util.ui.UIUtil; -import com.intellij.util.xmlb.XmlSerializerUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Date; - -/** - * User: Evgeny.Zakrevsky - * Date: 11/19/12 - */ - -@State( - name = "TimeTrackingManager", - storages = { - @Storage(file = StoragePathMacros.WORKSPACE_FILE) - } -) -public class TimeTrackingManager implements ProjectComponent, PersistentStateComponent<TimeTrackingManager.Config> { - - public static final int TIME_TRACKING_TIME_UNIT = 1000; - - private final Project myProject; - private final TaskManager myTaskManager; - private final Config myConfig = new Config(); - private Timer myTimeTrackingTimer; - private final Alarm myIdleAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - private Runnable myActivityListener; - private LocalTask myLastActiveTask; - - public TimeTrackingManager(Project project, - TaskManager taskManager) { - myProject = project; - myTaskManager = taskManager; - } - - public static TimeTrackingManager getInstance(Project project) { - return project.getComponent(TimeTrackingManager.class); - } - - private void startTimeTrackingTimer() { - if (!myTimeTrackingTimer.isRunning()) { - myTimeTrackingTimer.start(); - } - - myIdleAlarm.cancelAllRequests(); - myIdleAlarm.addRequest(new Runnable() { - @Override - public void run() { - if (myTimeTrackingTimer.isRunning()) { - myTimeTrackingTimer.stop(); - } - } - }, getState().suspendDelayInSeconds * 1000); - } - - public void updateTimeTrackingToolWindow() { - ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.TASKS); - if (isTimeTrackingToolWindowAvailable()) { - if (toolWindow == null) { - toolWindow = - ToolWindowManager.getInstance(myProject).registerToolWindow(ToolWindowId.TASKS, true, ToolWindowAnchor.RIGHT, myProject, true); - new TasksToolWindowFactory().createToolWindowContent(myProject, toolWindow); - } - final ToolWindow finalToolWindow = toolWindow; - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - finalToolWindow.setAvailable(true, null); - finalToolWindow.show(null); - finalToolWindow.activate(null); - } - }); - } - else { - if (toolWindow != null) { - final ToolWindow finalToolWindow = toolWindow; - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - finalToolWindow.setAvailable(false, null); - } - }); - } - } - } - - public boolean isTimeTrackingToolWindowAvailable() { - return getState().enabled; - } - - @Override - public void initComponent() { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - myTimeTrackingTimer = UIUtil.createNamedTimer("TaskManager time tracking", TIME_TRACKING_TIME_UNIT, new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - final LocalTask activeTask = myTaskManager.getActiveTask(); - if (myLastActiveTask != activeTask) { - activeTask.addWorkItem(new WorkItem(new Date())); - } - if (getState().autoMode) { - final WorkItem lastWorkItem = activeTask.getWorkItems().get(activeTask.getWorkItems().size() - 1); - lastWorkItem.duration += TIME_TRACKING_TIME_UNIT; - getState().totallyTimeSpent += TIME_TRACKING_TIME_UNIT; - } - else { - if (activeTask.isRunning()) { - final WorkItem lastWorkItem = activeTask.getWorkItems().get(activeTask.getWorkItems().size() - 1); - lastWorkItem.duration += TIME_TRACKING_TIME_UNIT; - getState().totallyTimeSpent += TIME_TRACKING_TIME_UNIT; - } - } - myLastActiveTask = activeTask; - } - }); - StartupManager.getInstance(myProject).registerStartupActivity(new Runnable() { - public void run() { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - startTimeTrackingTimer(); - } - }); - } - }); - - myActivityListener = new Runnable() { - @Override - public void run() { - final IdeFrame frame = IdeFocusManager.getGlobalInstance().getLastFocusedFrame(); - if (frame == null) return; - final Project project = frame.getProject(); - if (project == null || !myProject.equals(project)) return; - startTimeTrackingTimer(); - } - }; - if (getState().autoMode) { - IdeEventQueue.getInstance().addActivityListener(myActivityListener, myProject); - } - } - } - - public void setAutoMode(final boolean on) { - final boolean oldState = getState().autoMode; - if (on != oldState) { - getState().autoMode = on; - if (on) { - IdeEventQueue.getInstance().addActivityListener(myActivityListener, myProject); - } - else { - IdeEventQueue.getInstance().removeActivityListener(myActivityListener); - myIdleAlarm.cancelAllRequests(); - if (!myTimeTrackingTimer.isRunning()) { - myTimeTrackingTimer.start(); - } - } - } - } - - @Override - public void disposeComponent() { - if (myTimeTrackingTimer != null) { - myTimeTrackingTimer.stop(); - } - myIdleAlarm.cancelAllRequests(); - Disposer.dispose(myIdleAlarm); - } - - @NotNull - @Override - public String getComponentName() { - return "Time Tracking Manager"; - } - - @NotNull - @Override - public TimeTrackingManager.Config getState() { - return myConfig; - } - - @Override - public void loadState(final TimeTrackingManager.Config state) { - XmlSerializerUtil.copyBean(state, myConfig); - } - - @Override - public void projectOpened() { - } - - @Override - public void projectClosed() { - } - - public static class Config { - public boolean enabled = false; - public long totallyTimeSpent = 0; - public int suspendDelayInSeconds = 600; - public boolean autoMode = true; - public boolean showClosedTasks = true; - public boolean showSpentTimeFromLastPost = false; - } -} diff --git a/plugins/tasks/tasks-time-tracking/tasks-time-tracking.iml b/plugins/tasks/tasks-time-tracking/tasks-time-tracking.iml deleted file mode 100644 index ecee65315829..000000000000 --- a/plugins/tasks/tasks-time-tracking/tasks-time-tracking.iml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> - <exclude-output /> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="module" module-name="tasks-api" /> - <orderEntry type="module" module-name="tasks-core" /> - <orderEntry type="module" module-name="util" /> - <orderEntry type="module" module-name="core-api" /> - <orderEntry type="module" module-name="platform-api" /> - <orderEntry type="module" module-name="platform-impl" /> - <orderEntry type="module" module-name="lang-impl" /> - </component> -</module> - diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltBasicTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltBasicTest.java index e053411c15c4..7070314550e1 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltBasicTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltBasicTest.java @@ -15,9 +15,11 @@ */ package org.intellij.lang.xpath.xslt; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.xml.XmlFile; +import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; import org.intellij.lang.xpath.TestBase; import org.intellij.lang.xpath.xslt.impl.XsltChecker; @@ -91,7 +93,9 @@ public class XsltBasicTest extends TestBase { private void configure() throws Throwable { final String fileName = getTestFileName(); - myFixture.configureByFile(fileName.replaceAll("_.*$", "") + ".xsl"); + String path = fileName.replaceAll("_.*$", "") + ".xsl"; + final VirtualFile file = myFixture.copyFileToProject(path); + ((CodeInsightTestFixtureImpl)myFixture).openFileInEditor(file); if (fileName.endsWith("_Loaded")) { ((XmlFile)myFixture.getFile()).getDocument(); assertTrue(((PsiFileEx)myFixture.getFile()).isContentsLoaded()); diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java index 08f6041879b4..0c9eb2560f4b 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java @@ -15,7 +15,6 @@ */ package org.intellij.lang.xpath.xslt; -import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; @@ -126,8 +125,7 @@ public class XsltResolveTest extends TestBase { private PsiReference findInjectedReferenceAtCaret(String... moreFiles) throws Throwable { configure(moreFiles); - final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(myFixture.getProject()); - final PsiElement e = manager.findInjectedElementAt(myFixture.getFile(), myFixture.getEditor().getCaretModel().getOffset()); + final PsiElement e = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); assertNotNull(e); final PsiReference reference = e.getContainingFile().findReferenceAt(e.getTextOffset()); diff --git a/resources-en/src/inspectionDescriptions/ConstantConditions.html b/resources-en/src/inspectionDescriptions/ConstantConditions.html index 351ad1491158..1e2dd7644de7 100644 --- a/resources-en/src/inspectionDescriptions/ConstantConditions.html +++ b/resources-en/src/inspectionDescriptions/ConstantConditions.html @@ -1,11 +1,16 @@ <html> <body> -<font face="verdana" size="-1">This inspection reports those conditions in the specified inspection scope that are -always <b><font color="#000080">true</font></b> or <b><font color="#000080">false</font></b>, -as well as points out where a <b><font color="#000080">RuntimeException</font></b> may be thrown, -based on data flow analysis of the code.<br> -This inspection also reports Nullable/NotNull contract violations. -Annotations to support the contract can be configured (by default @Nullable/@NotNull annotations from annotations.jar will be used) -</font> +This inspection analyzes method control and data flow to report possible conditions that are always <b>true</b> or <b>false</b>, +expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations.<p/> + +Variables, method parameters and return values marked as <code>@Nullable</code> or <code>@NotNull</code> are treated as nullable (or not-null, respectively) +and used during the analysis to check nullability contracts, e.g. report possible <code>NullPointerException</code> errors.<p/> + +More complex contracts can be defined using <code>@Contract</code> annotation, for example:<p/> +<code>@Contract("_, null -> null")</code> — method returns null if its second argument is null<br/> +<code>@Contract("_, null -> null; _, !null -> !null")</code> — method returns null if its second argument is null and not-null otherwise<br/> +<code>@Contract("true -> fail")</code> — a typical <code>assertFalse</code> method which throws an exception if <code>true</code> is passed to it<br/> +<p/> +The inspection can be configured to use custom <code>@Nullable</code>/<code>@NotNull</code> annotations (by default the ones from annotations.jar will be used) </body> </html> diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 9c1d4fc51fe8..27c7454722e6 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -399,6 +399,9 @@ <applicationService serviceInterface="com.intellij.refactoring.JavaRefactoringSettings" serviceImplementation="com.intellij.refactoring.JavaRefactoringSettings"/> + <applicationService serviceInterface="com.intellij.codeInsight.generation.OverrideImplementExploreUtil$MemberImplementorExplorersProvider" + serviceImplementation="com.intellij.codeInsight.generation.MemberImplementorExplorersProviderImpl"/> + <projectService serviceInterface="com.intellij.refactoring.RefactoringManager" serviceImplementation="com.intellij.refactoring.RefactoringManager"/> <projectService serviceInterface="com.intellij.refactoring.listeners.JavaRefactoringListenerManager" diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index b745bef7c661..0acd60b36bc0 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -210,6 +210,7 @@ kotlin labeler labelers lcov +lcovonly ldap libxml lifecycle diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java index faca1b68ff9b..e5d15d5a9fd9 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubBuilderTest.java @@ -3,6 +3,7 @@ package com.intellij.util.xml.stubs; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.stubs.ObjectStubTree; import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.testFramework.PlatformTestUtil; @@ -54,7 +55,9 @@ public class DomStubBuilderTest extends DomStubTest { } public void testNullTag() throws Exception { - PsiFile psiFile = myFixture.configureByFile("nullTag.xml"); + VirtualFile virtualFile = myFixture.copyFileToProject("nullTag.xml"); + assertNotNull(virtualFile); + PsiFile psiFile = ((PsiManagerEx)getPsiManager()).getFileManager().findFile(virtualFile); StubTreeLoader loader = StubTreeLoader.getInstance(); VirtualFile file = psiFile.getVirtualFile(); diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java index 73b975d1a8cc..54983ba62ad1 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java @@ -18,6 +18,7 @@ package com.intellij.util.xml.stubs; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.stubs.ObjectStubTree; import com.intellij.psi.stubs.StubTreeLoader; @@ -28,7 +29,6 @@ import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomFileDescription; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.DomManager; -import com.intellij.util.xml.impl.DomApplicationComponent; import com.intellij.util.xml.impl.DomManagerImpl; import com.intellij.util.xml.stubs.model.Foo; @@ -93,10 +93,10 @@ public abstract class DomStubTest extends LightCodeInsightFixtureTestCase { } protected XmlFile prepareFile(String path) { - XmlFile file = (XmlFile)myFixture.configureByFile(path); - assertFalse(file.getNode().isParsed()); - VirtualFile virtualFile = file.getVirtualFile(); + VirtualFile virtualFile = myFixture.copyFileToProject(path); assertNotNull(virtualFile); + XmlFile file = (XmlFile)((PsiManagerEx)getPsiManager()).getFileManager().findFile(virtualFile); + assertFalse(file.getNode().isParsed()); ObjectStubTree tree = StubTreeLoader.getInstance().readOrBuild(getProject(), virtualFile, file); assertNotNull(tree); diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/references/FileReferenceUtil.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/references/FileReferenceUtil.java index 13ca07e55c3f..a5295ed4e32d 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/references/FileReferenceUtil.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/references/FileReferenceUtil.java @@ -44,6 +44,7 @@ public class FileReferenceUtil { final FileReference[] references = set.getAllReferences(); return ContainerUtil.map2Array(references, PsiReference.class, new NotNullFunction<FileReference, PsiReference>() { + @Override @NotNull public PsiReference fun(FileReference fileReference) { return new MyFileReference(fileReference, cond, soft); @@ -66,6 +67,7 @@ public class FileReferenceUtil { myType = type; } + @Override public boolean value(PsiFile file) { return file.getFileType() == myType; } @@ -78,6 +80,7 @@ public class FileReferenceUtil { myPattern = pattern; } + @Override public boolean value(PsiFile o) { return myPattern.accepts(o); } @@ -113,6 +116,7 @@ public class FileReferenceUtil { protected ResolveResult[] innerResolve() { final ResolveResult[] results = super.innerResolve(); return ContainerUtil.findAll(results, new Condition<ResolveResult>() { + @Override public boolean value(ResolveResult resolveResult) { final PsiElement e = resolveResult.getElement(); return match(e, myCond); @@ -125,6 +129,7 @@ public class FileReferenceUtil { public Object[] getVariants() { final Object[] variants = super.getVariants(); return ContainerUtil.findAll(variants, new Condition<Object>() { + @Override public boolean value(Object o) { /*if (o instanceof CandidateInfo) { o = ((CandidateInfo)o).getElement(); diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java index e86012369ebb..b054b7f9a2a5 100644 --- a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java +++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java @@ -9,7 +9,7 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.javaee.ExternalResourceManager; import com.intellij.javaee.ExternalResourceManagerEx; -import com.intellij.javaee.ExternalResourceManagerImpl; +import com.intellij.javaee.ExternalResourceManagerExImpl; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.PsiReference; @@ -23,6 +23,7 @@ import java.util.List; /** * @by Maxim.Mossienko */ +@SuppressWarnings("ConstantConditions") public class XmlCompletionTest extends LightCodeInsightFixtureTestCase { private String myOldDoctype; @@ -59,7 +60,7 @@ public class XmlCompletionTest extends LightCodeInsightFixtureTestCase { return; } - ExternalResourceManagerImpl.addTestResource(url, location, myTestRootDisposable); + ExternalResourceManagerExImpl.addTestResource(url, location, myTestRootDisposable); } @Override @@ -664,5 +665,10 @@ public class XmlCompletionTest extends LightCodeInsightFixtureTestCase { "xs:redefine", "xs:simpleType"); } + + public void testSubstitute() throws Exception { + myFixture.configureByFiles("Substitute/schema-a.xsd", "Substitute/schema-b.xsd"); + myFixture.testCompletionVariants("Substitute/test.xml", "b:instance", "instance"); + } } diff --git a/xml/tests/src/com/intellij/codeInsight/daemon/XmlHighlightingTest.java b/xml/tests/src/com/intellij/codeInsight/daemon/XmlHighlightingTest.java index 51e0ff29c816..0809eeb6d6eb 100644 --- a/xml/tests/src/com/intellij/codeInsight/daemon/XmlHighlightingTest.java +++ b/xml/tests/src/com/intellij/codeInsight/daemon/XmlHighlightingTest.java @@ -17,7 +17,7 @@ import com.intellij.ide.DataManager; import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.ide.highlighter.XmlHighlighterFactory; import com.intellij.javaee.ExternalResourceManagerEx; -import com.intellij.javaee.ExternalResourceManagerImpl; +import com.intellij.javaee.ExternalResourceManagerExImpl; import com.intellij.javaee.UriUtil; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.ant.dom.AntResolveInspection; @@ -35,7 +35,7 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.*; @@ -121,8 +121,8 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { final String url = "http://www.foo.org/schema"; final String url2 = "http://www.bar.org/foo"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, getTestName(false) + ".xsd", getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily(url2, getTestName(false) + ".xsd", getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, getTestName(false) + ".xsd", getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url2, getTestName(false) + ".xsd", getTestRootDisposable()); try { final Collection<HighlightInfo> infoCollection = doDoTest(true, false, true); final TextRange startTagNameRange = XmlTagUtil.getStartTagNameElement(((XmlFile)myFile).getDocument().getRootTag()).getTextRange(); @@ -243,8 +243,8 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { String url = "http://drools.org/rules"; String url2 = "http://drools.org/semantics/groovy"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily(url2, location2, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url2, location2, getTestRootDisposable()); final String basePath = BASE_PATH + testName; configureByFiles(null, getVirtualFile(basePath + ".xml"), getVirtualFile(basePath + ".xsd"), getVirtualFile(basePath + "_2.xsd")); doDoTest(true,false); @@ -327,8 +327,8 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { if (resources != null) { int curResource = 0; for(String[] resource:resources) { - ExternalResourceManagerImpl - .registerResourceTemporarily(resource[0], getTestDataPath() + BASE_PATH + resource[1], getTestRootDisposable()); + ExternalResourceManagerExImpl + .registerResourceTemporarily(resource[0], getTestDataPath() + BASE_PATH + resource[1], getTestRootDisposable()); testNames[++curResource] = BASE_PATH + resource[1]; } } @@ -484,8 +484,8 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { String url = "parent"; String url2 = "child"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily(url2, location2, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url2, location2, getTestRootDisposable()); configureByFiles(null, getVirtualFile(BASE_PATH + getTestName(false) + ".xml"), getVirtualFile(BASE_PATH + location), getVirtualFile(BASE_PATH + location2)); @@ -498,7 +498,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { configureByFiles(null, getVirtualFile(BASE_PATH + getTestName(false) + ".xml"), getVirtualFile(BASE_PATH + schemaLocation)); - ExternalResourceManagerImpl.registerResourceTemporarily(schemaLocation, schemaLocation, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(schemaLocation, schemaLocation, getTestRootDisposable()); doDoTest(true, false); } @@ -602,7 +602,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testXercesMessagesBinding2() throws Exception { final String url = getTestName(false) + ".xsd"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, url, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, url, getTestRootDisposable()); doTest( new VirtualFile[] { @@ -615,7 +615,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { final String url2 = getTestName(false) + "_2.xsd"; - ExternalResourceManagerImpl.registerResourceTemporarily(url2, url2, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url2, url2, getTestRootDisposable()); doTest( new VirtualFile[] { @@ -682,14 +682,14 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testStackOverflow() throws Exception { String location = "relaxng.xsd"; String url = "http://relaxng.org/ns/structure/fake/1.0"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); doTest(new VirtualFile[]{getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location)}, false, false); } public void testStackOverflow2() throws Exception { final String url = "urn:aaa"; final String location = getTestName(false) + ".xsd"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); doTest(getFullRelativeTestName(".xsd"), false, false); } @@ -707,7 +707,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testComplexDtdValidation() throws Exception { String location = "Tapestry_3_0.dtd"; String url = "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); myTestJustJaxpValidation = true; doTest(new VirtualFile[] { getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location) }, false,false); @@ -716,7 +716,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testComplexDtdValidation2() throws Exception { String location = getTestName(false)+".dtd"; - ExternalResourceManagerImpl.registerResourceTemporarily(location, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(location, location, getTestRootDisposable()); myTestJustJaxpValidation = true; doTest(new VirtualFile[] { getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location) }, false,false); @@ -734,7 +734,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { final VirtualFile virtualFile = getVirtualFile(BASE_PATH + "ComplexSchemaValidation3Schemas"); ContainerUtil.addAll(files, virtualFile.getChildren()); - doTest(VfsUtil.toVirtualFileArray(files), true, false); + doTest(VfsUtilCore.toVirtualFileArray(files), true, false); } public void testComplexSchemaValidation4() throws Exception { @@ -749,7 +749,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testComplexSchemaValidation5() throws Exception { String location = getTestName(false)+".xsd"; String url = "http://www.etas.com/TELEGY/Test"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); doTest(new VirtualFile[] { getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location) }, false,false); final XmlTag[] subTags = ((XmlFile)myFile).getDocument().getRootTag().getSubTags(); @@ -771,7 +771,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testComplexSchemaValidation6() throws Exception { String location = getTestName(false)+".xsd"; String url = "http://abcde/pg.html"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); doTest(new VirtualFile[]{getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location)}, true, false); } @@ -792,7 +792,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public boolean process(final List<VirtualFile> files) { try { files.set(0, getVirtualFile(BASE_PATH + getTestName(false) + "_2.xml")); - doTest(VfsUtil.toVirtualFileArray(files), true, false); + doTest(VfsUtilCore.toVirtualFileArray(files), true, false); return true; } catch (Exception e) { @@ -821,7 +821,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testErrorInDtd() throws Exception { String location = "def_xslt.dtd"; String url = "http://www.w3.org/1999/XSL/Transform"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); doTest(new VirtualFile[]{getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location)}, false, false); } @@ -1064,7 +1064,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testNonEnumeratedValuesHighlighting() throws Exception { final String url = "http://www.w3.org/1999/XSL/Format"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, "fop.xsd", getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, "fop.xsd", getTestRootDisposable()); configureByFiles(null, getVirtualFile(BASE_PATH + getTestName(false) + ".xml"), getVirtualFile(BASE_PATH + "fop.xsd")); doDoTest(true, false); } @@ -1314,9 +1314,9 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { final VirtualFile virtualFile = getVirtualFile(BASE_PATH + getTestName(false)); ContainerUtil.addAll(files, virtualFile.getChildren()); - ExternalResourceManagerImpl - .registerResourceTemporarily(url, UriUtil.findRelativeFile(mainDtdName, virtualFile).getPath(), getTestRootDisposable()); - doTest(VfsUtil.toVirtualFileArray(files), true, false); + ExternalResourceManagerExImpl + .registerResourceTemporarily(url, UriUtil.findRelativeFile(mainDtdName, virtualFile).getPath(), getTestRootDisposable()); + doTest(VfsUtilCore.toVirtualFileArray(files), true, false); if (additionalTestAction != null) additionalTestAction.run(); @@ -1337,7 +1337,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { final VirtualFile virtualFile = getVirtualFile(base + filename); usedFiles.add(virtualFile); - if (url != null) ExternalResourceManagerImpl.registerResourceTemporarily(url, virtualFile.getPath(), getTestRootDisposable()); + if (url != null) ExternalResourceManagerExImpl.registerResourceTemporarily(url, virtualFile.getPath(), getTestRootDisposable()); files.add( virtualFile ); } @@ -1347,7 +1347,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { } } - doTest(VfsUtil.toVirtualFileArray(files), true, false); + doTest(VfsUtilCore.toVirtualFileArray(files), true, false); if (additionalTestingProcessor != null) additionalTestingProcessor.process(files); } @@ -1391,7 +1391,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testSchemaUpdate() throws IOException { String location = getTestName(false)+".xsd"; String url = "http://example.org/ns/books/"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); configureByFiles(null, getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location)); doDoTest(true,false); @@ -1425,7 +1425,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { public void testSchemaValidation6() throws Exception { String location = getTestName(false)+".xsd"; String url = "aaa"; - ExternalResourceManagerImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily(url, location, getTestRootDisposable()); configureByFiles(null, getVirtualFile(getFullRelativeTestName()), getVirtualFile(BASE_PATH + location)); doDoTest(true,false); @@ -1794,8 +1794,8 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { } public void testSubstitutionFromInclude() throws Exception { - ExternalResourceManagerImpl - .registerResourceTemporarily("http://www.omg.org/spec/BPMN/20100524/MODEL", "BPMN20.xsd", getTestRootDisposable()); + ExternalResourceManagerExImpl + .registerResourceTemporarily("http://www.omg.org/spec/BPMN/20100524/MODEL", "BPMN20.xsd", getTestRootDisposable()); doTest( new VirtualFile[] { @@ -1819,7 +1819,7 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { {"http://www.w3.org/1999/xlink",path + "mylib.jar!/xlink.xsd"} }; - for(String[] s:urls) ExternalResourceManagerImpl.registerResourceTemporarily(s[0], s[1], getTestRootDisposable()); + for(String[] s:urls) ExternalResourceManagerExImpl.registerResourceTemporarily(s[0], s[1], getTestRootDisposable()); doDoTest(true, false); } @@ -1997,6 +1997,14 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { doDoTest(true, false); } + public void testSubstitution() throws Exception { + doTest(new VirtualFile[]{ + getVirtualFile(BASE_PATH + "Substitute/test.xml"), + getVirtualFile(BASE_PATH + "Substitute/schema-b.xsd"), + getVirtualFile(BASE_PATH + "Substitute/schema-a.xsd") + }, true, true); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -2004,54 +2012,54 @@ public class XmlHighlightingTest extends DaemonAnalyzerTestCase { old = XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS; XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS = false; - ExternalResourceManagerImpl.registerResourceTemporarily("http://www.springframework.org/schema/beans/spring-beans-2.5.xsd", - getTestDataPath() + BASE_PATH + "spring-beans-2.5.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", - getTestDataPath() + BASE_PATH + "web-app_2_4.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", - getTestDataPath() + BASE_PATH + "web-app_2_4.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/dtd/web-app_2_3.dtd", - getTestDataPath() + BASE_PATH + "web-app_2_3.dtd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://struts.apache.org/dtds/struts-config_1_2.dtd", - getTestDataPath() + BASE_PATH + "struts-config_1_2.dtd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/dtd/ejb-jar_2_0.dtd", - getTestDataPath() + BASE_PATH + "ejb-jar_2_0.dtd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/wsdl/", - getTestDataPath() + BASE_PATH + "wsdl11.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/wsdl/soap/", - getTestDataPath() + BASE_PATH + "wsdl11_soapbinding.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/soap/encoding/", - getTestDataPath() + BASE_PATH + "soap-encoding.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/application-client_1_4.xsd", - getTestDataPath() + BASE_PATH + "application-client_1_4.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd", - getTestDataPath() + BASE_PATH + "hibernate-mapping-3.0.dtd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://maven.apache.org/maven-v4_0_0.xsd", - getTestDataPath() + BASE_PATH + "maven-4.0.0.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd", - getTestDataPath() + BASE_PATH + "web-jsptaglibrary_1_2.dtd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/JSP/Page", - getTestDataPath() + BASE_PATH + "jsp_2_0.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd", - getTestDataPath() + BASE_PATH + "web-jsptaglibrary_2_0.xsd", - getTestRootDisposable()); - ExternalResourceManagerImpl.registerResourceTemporarily("http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd", - getTestDataPath() + BASE_PATH + "hibernate-configuration-3.0.dtd", - getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://www.springframework.org/schema/beans/spring-beans-2.5.xsd", + getTestDataPath() + BASE_PATH + "spring-beans-2.5.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", + getTestDataPath() + BASE_PATH + "web-app_2_4.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", + getTestDataPath() + BASE_PATH + "web-app_2_4.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/dtd/web-app_2_3.dtd", + getTestDataPath() + BASE_PATH + "web-app_2_3.dtd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://struts.apache.org/dtds/struts-config_1_2.dtd", + getTestDataPath() + BASE_PATH + "struts-config_1_2.dtd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/dtd/ejb-jar_2_0.dtd", + getTestDataPath() + BASE_PATH + "ejb-jar_2_0.dtd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/wsdl/", + getTestDataPath() + BASE_PATH + "wsdl11.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/wsdl/soap/", + getTestDataPath() + BASE_PATH + "wsdl11_soapbinding.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://schemas.xmlsoap.org/soap/encoding/", + getTestDataPath() + BASE_PATH + "soap-encoding.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/application-client_1_4.xsd", + getTestDataPath() + BASE_PATH + "application-client_1_4.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd", + getTestDataPath() + BASE_PATH + "hibernate-mapping-3.0.dtd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://maven.apache.org/maven-v4_0_0.xsd", + getTestDataPath() + BASE_PATH + "maven-4.0.0.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd", + getTestDataPath() + BASE_PATH + "web-jsptaglibrary_1_2.dtd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/JSP/Page", + getTestDataPath() + BASE_PATH + "jsp_2_0.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd", + getTestDataPath() + BASE_PATH + "web-jsptaglibrary_2_0.xsd", + getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd", + getTestDataPath() + BASE_PATH + "hibernate-configuration-3.0.dtd", + getTestRootDisposable()); } private void disableHtmlSupport() { diff --git a/xml/tests/testData/completion/Substitute/schema-a.xsd b/xml/tests/testData/completion/Substitute/schema-a.xsd new file mode 100644 index 000000000000..d359cf02280b --- /dev/null +++ b/xml/tests/testData/completion/Substitute/schema-a.xsd @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://test/a" + targetNamespace="http://test/a"> + + <xsd:complexType name="abstractType"> + <xsd:attribute name="id" type="xsd:string" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="Root"> + <xsd:sequence> + <xsd:element ref="a:instance" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="instance" type="a:abstractType"/> + <xsd:element name="root" type="a:Root"/> +</xsd:schema>
\ No newline at end of file diff --git a/xml/tests/testData/completion/Substitute/schema-b.xsd b/xml/tests/testData/completion/Substitute/schema-b.xsd new file mode 100644 index 000000000000..4581f360c571 --- /dev/null +++ b/xml/tests/testData/completion/Substitute/schema-b.xsd @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:b="http://test/b" + xmlns:a="http://test/a" + targetNamespace="http://test/b"> + <xsd:import namespace="http://test/a"/> + + <xsd:complexType name="subType"> + <xsd:complexContent> + <xsd:restriction base="a:abstractType"> + <xsd:attribute name="id" type="xsd:string" use="required"/> + </xsd:restriction> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="instance" type="b:subType" substitutionGroup="a:instance"/> +</xsd:schema>
\ No newline at end of file diff --git a/xml/tests/testData/completion/Substitute/test.xml b/xml/tests/testData/completion/Substitute/test.xml new file mode 100644 index 000000000000..0f6d6eb1a01c --- /dev/null +++ b/xml/tests/testData/completion/Substitute/test.xml @@ -0,0 +1,7 @@ +<root xmlns="http://test/a" + xmlns:b="http://test/b" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://test/b schema-b.xsd"> + + <<caret> +</root>
\ No newline at end of file diff --git a/xml/tests/testData/xml/Substitute/schema-a.xsd b/xml/tests/testData/xml/Substitute/schema-a.xsd new file mode 100644 index 000000000000..d359cf02280b --- /dev/null +++ b/xml/tests/testData/xml/Substitute/schema-a.xsd @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://test/a" + targetNamespace="http://test/a"> + + <xsd:complexType name="abstractType"> + <xsd:attribute name="id" type="xsd:string" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="Root"> + <xsd:sequence> + <xsd:element ref="a:instance" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="instance" type="a:abstractType"/> + <xsd:element name="root" type="a:Root"/> +</xsd:schema>
\ No newline at end of file diff --git a/xml/tests/testData/xml/Substitute/schema-b.xsd b/xml/tests/testData/xml/Substitute/schema-b.xsd new file mode 100644 index 000000000000..4581f360c571 --- /dev/null +++ b/xml/tests/testData/xml/Substitute/schema-b.xsd @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:b="http://test/b" + xmlns:a="http://test/a" + targetNamespace="http://test/b"> + <xsd:import namespace="http://test/a"/> + + <xsd:complexType name="subType"> + <xsd:complexContent> + <xsd:restriction base="a:abstractType"> + <xsd:attribute name="id" type="xsd:string" use="required"/> + </xsd:restriction> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="instance" type="b:subType" substitutionGroup="a:instance"/> +</xsd:schema>
\ No newline at end of file diff --git a/xml/tests/testData/xml/Substitute/test.xml b/xml/tests/testData/xml/Substitute/test.xml new file mode 100644 index 000000000000..557e2cb4a7c2 --- /dev/null +++ b/xml/tests/testData/xml/Substitute/test.xml @@ -0,0 +1,8 @@ +<root xmlns="http://test/a" + xmlns:b="http://test/b" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://test/b schema-b.xsd"> + + <instance/> + <b:instance id=""/> +</root>
\ No newline at end of file diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java index c2005fa4ba41..f4d468edf759 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java @@ -242,7 +242,7 @@ public class ComplexTypeDescriptor extends TypeDescriptor { return result.toArray(new XmlAttributeDescriptor[result.size()]); } - public XmlNSDescriptorImpl getNsDescriptors() { + public XmlNSDescriptorImpl getNsDescriptor() { return myDocumentDescriptor; } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/RedefinedElementDescriptor.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/RedefinedElementDescriptor.java index 75a96f6873f7..a3054b21fa00 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/RedefinedElementDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/RedefinedElementDescriptor.java @@ -26,7 +26,7 @@ public class RedefinedElementDescriptor extends XmlElementDescriptorImpl { private class RedefinedTypeDescriptor extends ComplexTypeDescriptor { public RedefinedTypeDescriptor(ComplexTypeDescriptor original) { - super(original.getNsDescriptors(), original.getDeclaration()); + super(original.getNsDescriptor(), original.getDeclaration()); } @Override diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/SchemaNSDescriptor.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/SchemaNSDescriptor.java index f45f3006039c..e5d7a19f59de 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/SchemaNSDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/SchemaNSDescriptor.java @@ -178,4 +178,9 @@ public class SchemaNSDescriptor extends XmlNSDescriptorImpl { } return descriptor; } + + @Override + public String toString() { + return getDefaultNamespace(); + } } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java index 91b8f60009a4..22f37c594056 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java @@ -20,7 +20,9 @@ import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.meta.PsiWritableMetaData; -import com.intellij.psi.util.*; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.ParameterizedCachedValueProvider; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; @@ -30,6 +32,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * @author Mike */ @@ -239,7 +245,29 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab if (type instanceof ComplexTypeDescriptor) { ComplexTypeDescriptor typeDescriptor = (ComplexTypeDescriptor)type; - return typeDescriptor.getElements(context); + XmlElementDescriptor[] elements = typeDescriptor.getElements(context); + if (context instanceof XmlTag && elements.length > 0) { + String[] namespaces = ((XmlTag)context).knownNamespaces(); + if (namespaces.length > 1) { + List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>(Arrays.asList(elements)); + for (String namespace : namespaces) { + if (namespace.equals(typeDescriptor.getNsDescriptor().getDefaultNamespace())) { + continue; + } + XmlNSDescriptor descriptor = ((XmlTag)context).getNSDescriptor(namespace, false); + if (descriptor instanceof XmlNSDescriptorImpl && ((XmlNSDescriptorImpl)descriptor).hasSubstitutions()) { + for (XmlElementDescriptor element : elements) { + String name = element.getName(context); + String s = ((XmlNSDescriptorImpl)element.getNSDescriptor()).getDefaultNamespace(); + XmlElementDescriptor[] substitutes = ((XmlNSDescriptorImpl)descriptor).getSubstitutes(name, s); + result.addAll(Arrays.asList(substitutes)); + } + } + } + return result.toArray(new XmlElementDescriptor[result.size()]); + } + } + return elements; } return EMPTY_ARRAY; @@ -403,10 +431,13 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab final XmlNSDescriptor descriptor = context instanceof XmlTag? ((XmlTag)context).getNSDescriptor(namespace, true) : null; // schema's targetNamespace could be different from file systemId used as NS - if (descriptor instanceof XmlNSDescriptorImpl && - ((XmlNSDescriptorImpl)descriptor).getDefaultNamespace().equals(namespaceByContext) - ) { - return element; + if (descriptor instanceof XmlNSDescriptorImpl) { + if (((XmlNSDescriptorImpl)descriptor).getDefaultNamespace().equals(namespaceByContext)) { + return element; + } + else { + ((XmlNSDescriptorImpl)descriptor).getSubstitutes(localName, namespace); + } } } } @@ -503,7 +534,7 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab if (type instanceof ComplexTypeDescriptor) { final ComplexTypeDescriptor typeDescriptor = (ComplexTypeDescriptor)type; return typeDescriptor.canContainTag("a", namespace, context) || - typeDescriptor.getNsDescriptors().hasSubstitutions() || + typeDescriptor.getNsDescriptor().hasSubstitutions() || XmlUtil.nsFromTemplateFramework(namespace) ; } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java index 157536762a5a..8b4c20a76c2c 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java @@ -34,7 +34,9 @@ import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import com.intellij.xml.XmlAttributeDescriptor; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlNSDescriptor; @@ -846,15 +848,15 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return findSpecialTag(name,"attributeGroup",myTag,this, null); } - private Map<String,List<XmlTag>> mySubstitutions; + private MultiMap<String,XmlTag> mySubstitutions; public XmlElementDescriptor[] getSubstitutes(String localName, String namespace) { - List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>(); - - initSubstitutes(); - - List<XmlTag> substitutions = mySubstitutions.get(localName); - if (substitutions==null) return XmlElementDescriptor.EMPTY_ARRAY; + if (!initSubstitutes()) { + return XmlElementDescriptor.EMPTY_ARRAY; + } + Collection<XmlTag> substitutions = mySubstitutions.get(localName); + if (substitutions.isEmpty()) return XmlElementDescriptor.EMPTY_ARRAY; + List<XmlElementDescriptor> result = new SmartList<XmlElementDescriptor>(); for (XmlTag tag : substitutions) { final String substAttr = tag.getAttributeValue("substitutionGroup"); if (substAttr != null && checkElementNameEquivalence(localName, namespace, substAttr, tag)) { @@ -865,9 +867,11 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return result.toArray(new XmlElementDescriptor[result.size()]); } - private void initSubstitutes() { - if (mySubstitutions ==null) { - mySubstitutions = new HashMap<String, List<XmlTag>>(); + private boolean initSubstitutes() { + if (mySubstitutions == null && myTag != null) { + mySubstitutions = new MultiMap<String, XmlTag>(); + + if (myTag == null) return false; XmlTag[] tags = myTag.getSubTags(); @@ -876,16 +880,12 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum final String substAttr = tag.getAttributeValue("substitutionGroup"); if (substAttr != null) { String substLocalName = XmlUtil.findLocalNameByQualifiedName(substAttr); - List<XmlTag> list = mySubstitutions.get(substLocalName); - if (list == null) { - list = new LinkedList<XmlTag>(); - mySubstitutions.put(substLocalName, list); - } - list.add(tag); + mySubstitutions.putValue(substLocalName, tag); } } } } + return mySubstitutions != null; } public PsiElement getDeclaration(){ |