diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form index b714b02857b4..aa9ca7fb74a4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.form @@ -1,117 +1,290 @@
- + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - - + - + - + - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + - - - - - - - - - - - - - - - - - - - + @@ -119,286 +292,125 @@ - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - + + - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java index e16066e5ddb9..c21ec1d2a3b3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointPropertiesPanel.java @@ -51,8 +51,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; @@ -178,6 +176,9 @@ public abstract class BreakpointPropertiesPanel { if (b) { myActionsPanel.setVisible(true); } + if (!b) { + myPanel.setPreferredSize(new Dimension(500, -1)); + } } public void setDelegate(Delegate delegate) { @@ -276,24 +277,6 @@ public abstract class BreakpointPropertiesPanel { myBreakpointComboboxHandler = new BreakpointComboboxHandler(myProject, baseBreakpointCombo); baseBreakpointCombo.setRenderer(new BreakpointComboRenderer(baseBreakpointCombo.getRenderer())); - baseBreakpointCombo.addPopupMenuListener(new PopupMenuListener() { - @Override - public void popupMenuWillBecomeVisible(PopupMenuEvent event) { - event.getClass();//To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public void popupMenuWillBecomeInvisible(PopupMenuEvent event) { - //To change body of implemented methods use File | Settings | File Templates. - event.getClass(); - } - - @Override - public void popupMenuCanceled(PopupMenuEvent event) { - //To change body of implemented methods use File | Settings | File Templates. - event.getClass(); - } - }); baseBreakpointCombo.addItemListener(new ItemListener() { public void itemStateChanged(final ItemEvent e) { ComboboxItem item = (ComboboxItem)baseBreakpointCombo.getSelectedItem(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java index c0fe968e9dd9..74febadb6647 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointItem.java @@ -48,15 +48,6 @@ class JavaBreakpointItem extends BreakpointItem { renderer.append(myBreakpoint.getShortName()); } - @Override - public void updateMnemonicLabel(JLabel label) { - //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public void execute(Project project, JBPopup popup) { - - } @Override public String speedSearchText() { diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ExistingModuleLoader.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ExistingModuleLoader.java index b0a84be1215b..cc651af9fbcf 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/ExistingModuleLoader.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/ExistingModuleLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ package com.intellij.ide.util.projectWizard; import com.intellij.CommonBundle; +import com.intellij.application.options.PathMacrosCollector; import com.intellij.application.options.PathMacrosImpl; import com.intellij.conversion.ConversionResult; import com.intellij.conversion.ConversionService; import com.intellij.ide.IdeBundle; import com.intellij.openapi.application.PathMacros; -import com.intellij.openapi.components.impl.stores.StorageUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; @@ -83,7 +83,7 @@ public class ExistingModuleLoader extends ModuleBuilder { } final Document document = JDOMUtil.loadDocument(file); final Element root = document.getRootElement(); - final Set usedMacros = StorageUtil.getMacroNames(root); + final Set usedMacros = PathMacrosCollector.getMacroNames(root); final Set definedMacros = PathMacros.getInstance().getAllMacroNames(); usedMacros.remove("$" + PathMacrosImpl.MODULE_DIR_MACRO_NAME + "$"); usedMacros.removeAll(definedMacros); diff --git a/java/idea-ui/src/com/intellij/openapi/components/impl/stores/IdeaProjectStoreImpl.java b/java/idea-ui/src/com/intellij/openapi/components/impl/stores/IdeaProjectStoreImpl.java index 6407ae5ac140..bd32731c8b39 100644 --- a/java/idea-ui/src/com/intellij/openapi/components/impl/stores/IdeaProjectStoreImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/components/impl/stores/IdeaProjectStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,11 +34,11 @@ public class IdeaProjectStoreImpl extends ProjectWithModulesStoreImpl { protected StateStorageManager createStateStorageManager() { return new ProjectStateStorageManager(PathMacroManager.getInstance(getComponentManager()).createTrackingSubstitutor(), myProject) { - public XmlElementStorage.StorageData createWsStorageData() { + public StorageData createWsStorageData() { return new IdeaWsStorageData(ROOT_TAG_NAME, myProject); } - public XmlElementStorage.StorageData createIprStorageData() { + public StorageData createIprStorageData() { return new IdeaIprStorageData(ROOT_TAG_NAME, myProject); } }; @@ -53,7 +53,7 @@ public class IdeaProjectStoreImpl extends ProjectWithModulesStoreImpl { super(storageData); } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new IdeaWsStorageData(this); } } @@ -68,7 +68,7 @@ public class IdeaProjectStoreImpl extends ProjectWithModulesStoreImpl { super(storageData); } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new IdeaIprStorageData(this); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/CreateModuleLibraryChooser.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/CreateModuleLibraryChooser.java index 50e207e796fb..40fc91d6802c 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/CreateModuleLibraryChooser.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/CreateModuleLibraryChooser.java @@ -23,10 +23,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.impl.libraries.LibraryEx; import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.roots.libraries.LibraryProperties; -import com.intellij.openapi.roots.libraries.LibraryTable; -import com.intellij.openapi.roots.libraries.LibraryType; +import com.intellij.openapi.roots.libraries.*; import com.intellij.openapi.roots.libraries.ui.LibraryRootsComponentDescriptor; import com.intellij.openapi.roots.libraries.ui.OrderRoot; import com.intellij.openapi.roots.libraries.ui.impl.RootDetectionUtil; @@ -82,8 +79,9 @@ public class CreateModuleLibraryChooser implements ClasspathElementChooser roots, final LibraryType libraryType) { - final Library library = ((LibraryTableBase.ModifiableModelEx)myModuleLibrariesModel).createLibrary(null, libraryType.getKind()); + private Library createLibraryFromRoots(List roots, @Nullable final LibraryType libraryType) { + final PersistentLibraryKind kind = libraryType == null ? null : libraryType.getKind(); + final Library library = ((LibraryTableBase.ModifiableModelEx)myModuleLibrariesModel).createLibrary(null, kind); final LibraryEx.ModifiableModelEx libModel = (LibraryEx.ModifiableModelEx)library.getModifiableModel(); if (myDefaultPropertiesFactory != null) { libModel.setProperties(myDefaultPropertiesFactory.fun(libraryType)); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java index 092a8be9c07d..ed1a4fa31a08 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/JdkConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.projectRoots.ui.SdkEditor; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; @@ -78,13 +79,13 @@ public class JdkConfigurable extends ProjectStructureElementConfigurable im } public Icon getIcon() { - return myProjectJdk.getSdkType().getIcon(); + return ((SdkType) myProjectJdk.getSdkType()).getIcon(); } @Nullable @NonNls public String getHelpTopic() { - return myProjectJdk.getSdkType().getHelpTopic(); + return ((SdkType) myProjectJdk.getSdkType()).getHelpTopic(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java index 6a8f8244faca..1f06435e398a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java @@ -21,15 +21,20 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class JavaChangeLocalityDetector implements ChangeLocalityDetector { @Override @Nullable - public PsiElement getChangeHighlightingDirtyScopeFor(final PsiElement element) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull final PsiElement element) { + // optimization PsiElement parent = element.getParent(); - if (element instanceof PsiCodeBlock && parent instanceof PsiMethod && !((PsiMethod)parent).isConstructor() && - parent.getParent() instanceof PsiClass && !(parent.getParent() instanceof PsiAnonymousClass)) { + if (element instanceof PsiCodeBlock + && parent instanceof PsiMethod + && !((PsiMethod)parent).isConstructor() + && parent.getParent() instanceof PsiClass + && !(parent.getParent() instanceof PsiAnonymousClass)) { // for changes inside method, rehighlight codeblock only // do not use this optimization for constructors and class initializers - to update non-initialized fields return parent; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 38c112b47e1b..a9647f8e6640 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -417,7 +417,7 @@ public class HighlightControlFlowUtil { if (codeBlockProblems == null) { try { final ControlFlow controlFlow = getControlFlow(topBlock); - codeBlockProblems = ControlFlowUtil.getReadBeforeWrite(controlFlow); + codeBlockProblems = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow); } catch (AnalysisCanceledException e) { codeBlockProblems = Collections.emptyList(); @@ -570,7 +570,7 @@ public class HighlightControlFlowUtil { } @NotNull - private static Collection getFinalVariableProblemsInBlock(Map> finalVarProblems, PsiElement codeBlock) { + public static Collection getFinalVariableProblemsInBlock(Map> finalVarProblems, PsiElement codeBlock) { Collection codeBlockProblems = finalVarProblems.get(codeBlock); if (codeBlockProblems == null) { try { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java index 13f3d21348dd..337db3857199 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -320,7 +320,7 @@ public class GenerateMembersUtil { super.visitReferenceElement(reference); final PsiElement resolve = reference.resolve(); if (resolve instanceof PsiTypeParameter) { - replacementMap.put(reference, factory.createReferenceElementByType((PsiClassType)substitutor.substitute((PsiTypeParameter)resolve))); + replacementMap.put(reference, factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, factory.createType((PsiTypeParameter)resolve)))); } } }); diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java new file mode 100644 index 000000000000..149beec691dc --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java @@ -0,0 +1,269 @@ +/* + * 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.codeInspection.varScopeCanBeNarrowed; + +import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.*; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.IJSwingUtilities; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NotNullFunction; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Set; + +/** + * refactored from {@link com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection.MyQuickFix} + * + * @author Danila Ponomarenko + */ +public abstract class BaseConvertToLocalQuickFix implements LocalQuickFix { + private static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); + + @NotNull + public final String getName() { + return InspectionsBundle.message("inspection.convert.to.local.quickfix"); + } + + public final void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final V variable = getVariable(descriptor); + final PsiFile myFile = variable.getContainingFile(); + if (variable == null || !variable.isValid()) return; //weird. should not get here when field becomes invalid + + try { + final PsiElement newDeclaration = moveDeclaration(project, variable); + if (newDeclaration == null) return; + + positionCaretToDeclaration(project, myFile, newDeclaration); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + + @Nullable + protected abstract V getVariable(@NotNull ProblemDescriptor descriptor); + + private static void positionCaretToDeclaration(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull PsiElement declaration) { + final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + if (editor != null && (IJSwingUtilities.hasFocus(editor.getComponent()) || ApplicationManager.getApplication().isUnitTestMode())) { + final PsiFile openedFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (openedFile == psiFile) { + editor.getCaretModel().moveToOffset(declaration.getTextOffset()); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } + } + } + + protected void beforeDelete(@NotNull Project project, @NotNull V variable, @NotNull PsiElement newDeclaration) { + } + + @Nullable + private PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { + final Collection references = ReferencesSearch.search(variable).findAll(); + if (references.isEmpty()) return null; + + final PsiCodeBlock anchorBlock = findAnchorBlock(references); + if (anchorBlock == null) return null; //was assert, but need to fix the case when obsolete inspection highlighting is left + if (!CodeInsightUtil.preparePsiElementsForWrite(anchorBlock)) return null; + + final PsiElement firstElement = getLowestOffsetElement(references); + final String localName = suggestLocalName(project, variable, anchorBlock); + + final PsiElement anchor = getAnchorElement(anchorBlock, firstElement); + + + final PsiAssignmentExpression anchorAssignmentExpression = searchAssignmentExpression(anchor); + if (anchorAssignmentExpression != null && isVariableAssignment(anchorAssignmentExpression, variable)) { + final Set refsSet = new HashSet(references); + refsSet.remove(anchorAssignmentExpression.getLExpression()); + return applyChanges( + project, + localName, + anchorAssignmentExpression.getRExpression(), + variable, + refsSet, + new NotNullFunction() { + @NotNull + @Override + public PsiElement fun(PsiDeclarationStatement declaration) { + if (!mayBeFinal(firstElement, references)) { + PsiUtil.setModifierProperty((PsiModifierListOwner)declaration.getDeclaredElements()[0], PsiModifier.FINAL, false); + } + return anchor.replace(declaration); + } + } + ); + } + + return applyChanges( + project, + localName, + variable.getInitializer(), + variable, + references, + new NotNullFunction() { + @NotNull + @Override + public PsiElement fun(PsiDeclarationStatement declaration) { + return anchorBlock.addBefore(declaration, anchor); + } + } + ); + } + + @NotNull + private PsiElement applyChanges(final @NotNull Project project, + final @NotNull String localName, + final @Nullable PsiExpression initializer, + final @NotNull V variable, + final @NotNull Collection references, + final @NotNull NotNullFunction action) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + + return ApplicationManager.getApplication().runWriteAction( + new Computable() { + @Override + public PsiElement compute() { + final PsiDeclarationStatement declaration = + elementFactory.createVariableDeclarationStatement(localName, variable.getType(), initializer); + final PsiElement newDeclaration = action.fun(declaration); + retargetReferences(elementFactory, localName, references); + beforeDelete(project, variable, newDeclaration); + variable.normalizeDeclaration(); + variable.delete(); + return newDeclaration; + } + } + ); + } + + @Nullable + private static PsiAssignmentExpression searchAssignmentExpression(@NotNull PsiElement anchor) { + if (!(anchor instanceof PsiExpressionStatement)) { + return null; + } + + final PsiExpression anchorExpression = ((PsiExpressionStatement)anchor).getExpression(); + + if (!(anchorExpression instanceof PsiAssignmentExpression)) { + return null; + } + + return (PsiAssignmentExpression)anchorExpression; + } + + private static boolean isVariableAssignment(@NotNull PsiAssignmentExpression expression, @NotNull PsiVariable variable) { + if (expression.getOperationTokenType() != JavaTokenType.EQ) { + return false; + } + + if (!(expression.getLExpression() instanceof PsiReferenceExpression)) { + return false; + } + + final PsiReferenceExpression leftExpression = (PsiReferenceExpression)expression.getLExpression(); + + if (!leftExpression.isReferenceTo(variable)) { + return false; + } + + return true; + } + + @NotNull + protected abstract String suggestLocalName(@NotNull Project project, @NotNull V variable, @NotNull PsiCodeBlock scope); + + private static boolean mayBeFinal(PsiElement firstElement, @NotNull Collection references) { + for (PsiReference reference : references) { + final PsiElement element = reference.getElement(); + if (element == firstElement) continue; + if (element instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression)element)) return false; + } + return true; + } + + private static void retargetReferences(PsiElementFactory elementFactory, String localName, Collection refs) + throws IncorrectOperationException { + final PsiReferenceExpression refExpr = (PsiReferenceExpression)elementFactory.createExpressionFromText(localName, null); + for (PsiReference ref : refs) { + if (ref instanceof PsiReferenceExpression) { + ((PsiReferenceExpression)ref).replace(refExpr); + } + } + } + + @NotNull + public String getFamilyName() { + return getName(); + } + + private static PsiElement getAnchorElement(PsiCodeBlock anchorBlock, @NotNull PsiElement firstElement) { + PsiElement element = firstElement; + while (element != null && element.getParent() != anchorBlock) { + element = element.getParent(); + } + return element; + } + + @Nullable + private static PsiElement getLowestOffsetElement(@NotNull Collection refs) { + PsiElement firstElement = null; + for (PsiReference reference : refs) { + final PsiElement element = reference.getElement(); + if (firstElement == null || firstElement.getTextRange().getStartOffset() > element.getTextRange().getStartOffset()) { + firstElement = element; + } + } + return firstElement; + } + + private static PsiCodeBlock findAnchorBlock(final Collection refs) { + PsiCodeBlock result = null; + for (PsiReference psiReference : refs) { + final PsiElement element = psiReference.getElement(); + PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); + if (result == null || block == null) { + result = block; + } + else { + final PsiElement commonParent = PsiTreeUtil.findCommonParent(result, block); + result = PsiTreeUtil.getParentOfType(commonParent, PsiCodeBlock.class, false); + } + } + return result; + } + + + public boolean runForWholeFile() { + return true; + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index d2966bcdca3f..f9e84420a033 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -16,21 +16,15 @@ package com.intellij.codeInspection.varScopeCanBeNarrowed; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.ImplicitUsageProvider; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.lang.java.JavaCommenter; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMExternalizableStringList; @@ -41,13 +35,9 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.*; import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; -import com.intellij.util.IJSwingUtilities; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.HashSet; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -65,8 +55,6 @@ import java.util.Set; * @author ven */ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection"); - @NonNls public static final String SHORT_NAME = "FieldCanBeLocal"; public final JDOMExternalizableStringList EXCLUDE_ANNOS = new JDOMExternalizableStringList(); @@ -110,13 +98,13 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { @Override public void visitJavaFile(PsiJavaFile file) { for (PsiClass aClass : file.getClasses()) { - docheckClass(aClass, holder, EXCLUDE_ANNOS); + doCheckClass(aClass, holder, EXCLUDE_ANNOS); } } }; } - private static void docheckClass(final PsiClass aClass, ProblemsHolder holder, final List excludeAnnos) { + private static void doCheckClass(final PsiClass aClass, ProblemsHolder holder, final List excludeAnnos) { if (aClass.isInterface()) return; final PsiField[] fields = aClass.getFields(); final Set candidates = new LinkedHashSet(); @@ -129,6 +117,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { } } + removeFieldsReferencedFromInitializers(aClass, candidates); if (candidates.isEmpty()) return; @@ -141,7 +130,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { for (PsiField field : candidates) { if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) { final String message = InspectionsBundle.message("inspection.field.can.be.local.problem.descriptor"); - holder.registerProblem(field.getNameIdentifier(), message, new MyQuickFix()); + holder.registerProblem(field.getNameIdentifier(), message, new ConvertFieldToLocalQuickFix()); } } } @@ -189,7 +178,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { final PsiElement resolved = readBeforeWrite.resolve(); if (resolved instanceof PsiField) { final PsiField field = (PsiField)resolved; - if (!isImmutableState(field.getType()) || !PsiUtil.isConstantExpression(field.getInitializer()) || getWrittenVariables(controlFlow, writtenVariables).contains(field)){ + if (!isImmutableState(field.getType()) || !PsiUtil.isConstantExpression(field.getInitializer()) || getWrittenVariables(controlFlow, writtenVariables).contains(field)) { PsiElement parent = body.getParent(); if (!(parent instanceof PsiMethod) || !((PsiMethod)parent).isConstructor() || @@ -222,15 +211,18 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { private static void removeFieldsReferencedFromInitializers(final PsiClass aClass, final Set candidates) { aClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitMethod(PsiMethod method) { + @Override + public void visitMethod(PsiMethod method) { //do not go inside method } - @Override public void visitClassInitializer(PsiClassInitializer initializer) { + @Override + public void visitClassInitializer(PsiClassInitializer initializer) { //do not go inside class initializer } - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { final PsiElement resolved = expression.resolve(); if (resolved instanceof PsiField) { final PsiField field = (PsiField)resolved; @@ -245,7 +237,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { } private static boolean hasImplicitReadOrWriteUsage(final PsiField field, ImplicitUsageProvider[] implicitUsageProviders) { - for(ImplicitUsageProvider provider: implicitUsageProviders) { + for (ImplicitUsageProvider provider : implicitUsageProviders) { if (provider.isImplicitRead(field) || provider.isImplicitWrite(field)) { return true; } @@ -253,173 +245,41 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { return false; } - private static class MyQuickFix implements LocalQuickFix { - @NotNull - public String getName() { - return InspectionsBundle.message("inspection.field.can.be.local.quickfix"); + private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix { + + @Override + @Nullable + protected PsiField getVariable(@NotNull ProblemDescriptor descriptor) { + return PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiField.class); } - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - PsiField myField = PsiTreeUtil.getParentOfType(element, PsiField.class); - if (myField == null || !myField.isValid()) return; //weird. should not get here when field becomes invalid + @Override + protected void beforeDelete(@NotNull Project project, @NotNull PsiField variable, @NotNull PsiElement newDeclaration) { + final PsiDocComment docComment = variable.getDocComment(); + if (docComment != null) moveDocCommentToDeclaration(project, docComment, newDeclaration); + } - final PsiDocComment docComment = myField.getDocComment(); - final Collection refs = ReferencesSearch.search(myField).findAll(); - if (refs.isEmpty()) return; - Set refsSet = new HashSet(refs); - PsiCodeBlock anchorBlock = findAnchorBlock(refs); - if (anchorBlock == null) return; //was assert, but need to fix the case when obsolete inspection highlighting is left - if (!CodeInsightUtil.preparePsiElementsForWrite(anchorBlock)) return; - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); + @NotNull + @Override + protected String suggestLocalName(@NotNull Project project, @NotNull PsiField field, @NotNull PsiCodeBlock scope) { final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project); - final String propertyName = styleManager.variableNameToPropertyName(myField.getName(), VariableKind.FIELD); - String localName = styleManager.propertyNameToVariableName(propertyName, VariableKind.LOCAL_VARIABLE); - localName = RefactoringUtil.suggestUniqueVariableName(localName, anchorBlock, myField); - PsiElement firstElement = getFirstElement(refs); - boolean mayBeFinal = mayBeFinal(refsSet, firstElement); - PsiElement newDeclaration = null; - try { - final PsiElement anchor = getAnchorElement(anchorBlock, firstElement); - if (anchor instanceof PsiExpressionStatement && - ((PsiExpressionStatement) anchor).getExpression() instanceof PsiAssignmentExpression) { - final PsiAssignmentExpression expression = (PsiAssignmentExpression) ((PsiExpressionStatement) anchor).getExpression(); - if (expression.getOperationTokenType() == JavaTokenType.EQ && - expression.getLExpression() instanceof PsiReferenceExpression && - ((PsiReference)expression.getLExpression()).isReferenceTo(myField)) { - final PsiExpression initializer = expression.getRExpression(); - final PsiDeclarationStatement decl = elementFactory.createVariableDeclarationStatement(localName, myField.getType(), initializer); - if (!mayBeFinal) { - PsiUtil.setModifierProperty((PsiModifierListOwner)decl.getDeclaredElements()[0], PsiModifier.FINAL, false); - } - newDeclaration = anchor.replace(decl); - refsSet.remove(expression.getLExpression()); - retargetReferences(elementFactory, localName, refsSet); - } - else { - newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet, - myField); - } - } - else { - newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet, - myField); - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - - if (newDeclaration != null) { - if (docComment != null) { - final StringBuilder buf = new StringBuilder(); - for (PsiElement psiElement : docComment.getDescriptionElements()) { - buf.append(psiElement.getText()); - } - if (buf.length() > 0) { - final JavaCommenter commenter = new JavaCommenter(); - final PsiComment comment = JavaPsiFacade.getElementFactory(project) - .createCommentFromText(commenter.getBlockCommentPrefix() + - buf.toString() + - commenter.getBlockCommentSuffix(), newDeclaration); - newDeclaration.getParent().addBefore(comment, newDeclaration); - } - } - final PsiFile psiFile = myField.getContainingFile(); - final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - if (editor != null && IJSwingUtilities.hasFocus(editor.getComponent())) { - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - if (file == psiFile) { - editor.getCaretModel().moveToOffset(newDeclaration.getTextOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - } - } - } - - try { - myField.normalizeDeclaration(); - myField.delete(); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + final String propertyName = styleManager.variableNameToPropertyName(field.getName(), VariableKind.FIELD); + final String localName = styleManager.propertyNameToVariableName(propertyName, VariableKind.LOCAL_VARIABLE); + return RefactoringUtil.suggestUniqueVariableName(localName, scope, field); } - private static boolean mayBeFinal(Set refsSet, PsiElement firstElement) { - for (PsiReference ref : refsSet) { - PsiElement element = ref.getElement(); - if (element == firstElement) continue; - if (element instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression) element)) return false; + private static void moveDocCommentToDeclaration(@NotNull Project project, @NotNull PsiDocComment docComment, @NotNull PsiElement declaration) { + final StringBuilder buf = new StringBuilder(); + for (PsiElement psiElement : docComment.getDescriptionElements()) { + buf.append(psiElement.getText()); } - return true; - } - - private static void retargetReferences(final PsiElementFactory elementFactory, final String localName, final Set refs) - throws IncorrectOperationException { - final PsiReferenceExpression refExpr = (PsiReferenceExpression)elementFactory.createExpressionFromText(localName, null); - for (PsiReference ref : refs) { - if (ref instanceof PsiReferenceExpression) { - ((PsiReferenceExpression)ref).replace(refExpr); - } + if (buf.length() > 0) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + final JavaCommenter commenter = new JavaCommenter(); + final PsiComment comment = elementFactory.createCommentFromText(commenter.getBlockCommentPrefix() + buf.toString() + commenter.getBlockCommentSuffix(), declaration); + declaration.getParent().addBefore(comment, declaration); } } - - private static PsiElement addDeclarationWithFieldInitializerAndRetargetReferences(final PsiElementFactory elementFactory, - final String localName, - final PsiCodeBlock anchorBlock, - final PsiElement anchor, - final Set refs, - PsiField myField) - throws IncorrectOperationException { - final PsiDeclarationStatement decl = elementFactory.createVariableDeclarationStatement(localName, myField.getType(), myField.getInitializer()); - final PsiElement newDeclaration = anchorBlock.addBefore(decl, anchor); - - retargetReferences(elementFactory, localName, refs); - return newDeclaration; - } - - @NotNull - public String getFamilyName() { - return getName(); - } - - private static PsiElement getAnchorElement(final PsiCodeBlock anchorBlock, @NotNull PsiElement firstElement) { - PsiElement element = firstElement; - while (element != null && element.getParent() != anchorBlock) { - element = element.getParent(); - } - return element; - } - - private static PsiElement getFirstElement(Collection refs) { - PsiElement firstElement = null; - for (PsiReference reference : refs) { - final PsiElement element = reference.getElement(); - if (firstElement == null || firstElement.getTextRange().getStartOffset() > element.getTextRange().getStartOffset()) { - firstElement = element; - } - } - return firstElement; - } - - private static PsiCodeBlock findAnchorBlock(final Collection refs) { - PsiCodeBlock result = null; - for (PsiReference psiReference : refs) { - final PsiElement element = psiReference.getElement(); - PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); - if (result == null || block == null) { - result = block; - } - else { - final PsiElement commonParent = PsiTreeUtil.findCommonParent(result, block); - result = PsiTreeUtil.getParentOfType(commonParent, PsiCodeBlock.class, false); - } - } - return result; - } } - public boolean runForWholeFile() { - return true; - } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java new file mode 100644 index 000000000000..97b9855402fa --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java @@ -0,0 +1,151 @@ +/* + * 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.codeInspection.varScopeCanBeNarrowed; + +import com.intellij.codeInsight.daemon.GroupNames; +import com.intellij.codeInspection.*; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.controlFlow.*; +import com.intellij.psi.search.searches.SuperMethodsSearch; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Danila Ponomarenko + */ +public class ParameterCanBeLocalInspection extends BaseJavaLocalInspectionTool { + + @NonNls public static final String SHORT_NAME = "ParameterCanBeLocal"; + + @NotNull + public String getGroupDisplayName() { + return GroupNames.CLASS_LAYOUT_GROUP_NAME; + } + + @NotNull + public String getDisplayName() { + return InspectionsBundle.message("inspection.parameter.can.be.local.display.name"); + } + + @NotNull + public String getShortName() { + return SHORT_NAME; + } + + @Override + public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { + final Collection parameters = filterFinal(method.getParameterList().getParameters()); + final PsiCodeBlock body = method.getBody(); + if (body == null || parameters.isEmpty() || isOverrides(method)) { + return ProblemDescriptor.EMPTY_ARRAY; + } + + final List result = new ArrayList(); + for (PsiParameter parameter : getWriteBeforeRead(parameters, body)) { + final PsiIdentifier identifier = parameter.getNameIdentifier(); + if (identifier != null) { + result.add(createProblem(manager, identifier, isOnTheFly)); + } + } + return result.toArray(new ProblemDescriptor[result.size()]); + } + + @NotNull + private static List filterFinal(PsiParameter[] parameters) { + final List result = new ArrayList(parameters.length); + for (PsiParameter parameter : parameters) { + if (!parameter.hasModifierProperty(PsiModifier.FINAL)) { + result.add(parameter); + } + } + return result; + } + + + @NotNull + private static ProblemDescriptor createProblem(@NotNull InspectionManager manager, + @NotNull PsiIdentifier identifier, + boolean isOnTheFly) { + return manager.createProblemDescriptor( + identifier, + InspectionsBundle.message("inspection.parameter.can.be.local.problem.descriptor"), + true, + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + isOnTheFly, + new ConvertParameterToLocalQuickFix() + ); + } + + private static Collection getWriteBeforeRead(@NotNull Collection parameters, + @NotNull PsiCodeBlock body) { + final ControlFlow controlFlow = getControlFlow(body); + if (controlFlow == null) return Collections.emptyList(); + + final Set result = filterParameters(controlFlow, parameters); + for (final PsiReferenceExpression readBeforeWrite : ControlFlowUtil.getReadBeforeWrite(controlFlow)) { + final PsiElement resolved = readBeforeWrite.resolve(); + if (resolved instanceof PsiParameter) { + result.remove((PsiParameter)resolved); + } + } + + return result; + } + + private static Set filterParameters(@NotNull ControlFlow controlFlow, @NotNull Collection parameters) { + final Set usedVars = new HashSet(ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize())); + + final Set result = new HashSet(); + for (PsiParameter parameter : parameters) { + if (usedVars.contains(parameter)) { + result.add(parameter); + } + } + return result; + } + + private static boolean isOverrides(PsiMethod method) { + return SuperMethodsSearch.search(method, null, true, false).findFirst() != null; + } + + @Nullable + private static ControlFlow getControlFlow(final PsiElement context) { + try { + return ControlFlowFactory.getInstance(context.getProject()) + .getControlFlow(context, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); + } + catch (AnalysisCanceledException e) { + return null; + } + } + + public static class ConvertParameterToLocalQuickFix extends BaseConvertToLocalQuickFix { + @Override + protected PsiParameter getVariable(@NotNull ProblemDescriptor descriptor) { + return (PsiParameter)descriptor.getPsiElement().getParent(); + } + + @NotNull + @Override + protected String suggestLocalName(@NotNull Project project, @NotNull PsiParameter parameter, @NotNull PsiCodeBlock scope) { + return parameter.getName(); + } + } +} diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index 8aa627ac4073..658164e9ec14 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -132,7 +132,6 @@ public class DefUseUtil { if (body == null) { return null; } - List unusedDefs = new ArrayList(); ControlFlow flow; try { @@ -223,6 +222,8 @@ public class DefUseUtil { } } + List unusedDefs = new ArrayList(); + for (int i = 0; i < instructions.size(); i++) { Instruction instruction = instructions.get(i); if (instruction instanceof WriteVariableInstruction) { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java index 31fbe26be597..b762395a7a2a 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java @@ -57,11 +57,11 @@ class InlineToAnonymousConstructorProcessor { psiElement().withText(PsiKeyword.THIS))); private final PsiClass myClass; - private final PsiNewExpression myNewExpression; + private PsiNewExpression myNewExpression; private final PsiType mySuperType; private final Map myFieldInitializers = new HashMap(); private final Map myLocalsForParameters = new HashMap(); - private final PsiStatement myNewStatement; + private PsiStatement myNewStatement; private final PsiElementFactory myElementFactory; private PsiMethod myConstructor; private PsiExpressionList myConstructorArguments; @@ -263,7 +263,23 @@ class InlineToAnonymousConstructorProcessor { final PsiDeclarationStatement declaration = myElementFactory.createVariableDeclarationStatement(localName, type, initializer); PsiVariable variable = (PsiVariable)declaration.getDeclaredElements()[0]; PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true); - myNewStatement.getParent().addBefore(declaration, myNewStatement); + final PsiElement parent = myNewStatement.getParent(); + if (parent instanceof PsiCodeBlock) { + variable = (PsiVariable)((PsiDeclarationStatement)parent.addBefore(declaration, myNewStatement)).getDeclaredElements()[0]; + } + else { + final int offsetInStatement = myNewExpression.getTextRange().getStartOffset() - myNewStatement.getTextRange().getStartOffset(); + final PsiBlockStatement blockStatement = (PsiBlockStatement)myElementFactory.createStatementFromText("{}", null); + PsiCodeBlock block = blockStatement.getCodeBlock(); + block.add(declaration); + block.add(myNewStatement); + block = ((PsiBlockStatement)myNewStatement.replace(blockStatement)).getCodeBlock(); + + variable = (PsiVariable)((PsiDeclarationStatement)block.getStatements()[0]).getDeclaredElements()[0]; + myNewStatement = block.getStatements()[1]; + myNewExpression = PsiTreeUtil.getParentOfType(myNewStatement.findElementAt(offsetInStatement), PsiNewExpression.class); + } + return variable; } catch (IncorrectOperationException e) { diff --git a/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java b/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java index 3e6487879d67..ff2dcc2b1ec9 100644 --- a/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java +++ b/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java @@ -136,4 +136,13 @@ public interface JVMElementFactory { @NotNull PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes); + + /** + * Creates a class type for the specified class. + * + * @param aClass the class for which the class type is created. + * @return the class type instance. + */ + @NotNull + PsiClassType createType(@NotNull PsiClass aClass); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java b/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java index 333b7b9e94ab..c90c49489137 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java @@ -154,14 +154,6 @@ public interface PsiElementFactory extends PsiJavaParserFacade, JVMElementFactor */ @NotNull PsiCodeBlock createCodeBlock(); - /** - * Creates a class type for the specified class. - * - * @param aClass the class for which the class type is created. - * @return the class type instance. - */ - @NotNull PsiClassType createType(@NotNull PsiClass aClass); - /** * Creates a class type for the specified class, using the specified substitutor * to replace generic type parameters on the class. diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index b9938c174104..9d69c8eed47b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -26,6 +26,7 @@ import com.intellij.util.containers.IntArrayList; import gnu.trove.THashSet; import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -73,7 +74,7 @@ public class ControlFlowUtil { } public static List getSSAVariables(ControlFlow flow, int from, int to, - boolean reportVarsIfNonInitializingPathExists) { + boolean reportVarsIfNonInitializingPathExists) { List instructions = flow.getInstructions(); Collection writtenVariables = getWrittenVariables(flow, from, to, false); ArrayList result = new ArrayList(1); @@ -147,23 +148,25 @@ public class ControlFlowUtil { private static boolean needVariableValueAt(final PsiVariable variable, final ControlFlow flow, final int offset) { InstructionClientVisitor visitor = new InstructionClientVisitor() { - final boolean[] neededBelow = new boolean[flow.getSize()+1]; + final boolean[] neededBelow = new boolean[flow.getSize() + 1]; @Override public void procedureEntered(int startOffset, int endOffset) { for (int i = startOffset; i < endOffset; i++) neededBelow[i] = false; } - @Override public void visitReadVariableInstruction(ReadVariableInstruction instruction, int offset, int nextOffset) { + @Override + public void visitReadVariableInstruction(ReadVariableInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean needed = neededBelow[nextOffset]; if (instruction.variable.equals(variable)) { - needed = true; + needed = true; } neededBelow[offset] |= needed; } - @Override public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { + @Override + public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean needed = neededBelow[nextOffset]; if (instruction.variable.equals(variable)) { @@ -172,7 +175,8 @@ public class ControlFlowUtil { neededBelow[offset] = needed; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean needed = neededBelow[nextOffset]; neededBelow[offset] |= needed; @@ -182,7 +186,7 @@ public class ControlFlowUtil { public Boolean getResult() { return neededBelow[offset]; } - }; + }; depthFirstSearch(flow, visitor, offset, flow.getSize()); return visitor.getResult().booleanValue(); } @@ -267,26 +271,33 @@ public class ControlFlowUtil { } final Collection exitStatements = new THashSet(); InstructionClientVisitor visitor = new InstructionClientVisitor() { - @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { //[ven]This is a hack since Extract Method doesn't want to see throw's exit points processGotoStatement(classesFilter, exitStatements, findStatement(flow, offset)); } - @Override public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) { + @Override + public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) { processGoto(flow, start, end, exitPoints, exitStatements, instruction, classesFilter, findStatement(flow, offset)); } // call/return do not incur exit points - @Override public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) { - } - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) { } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + } + + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { visitInstruction(instruction, offset, nextOffset); } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (offset >= end - 1) { int exitOffset = end; exitOffset = promoteThroughGotoChain(flow, exitOffset); @@ -319,7 +330,8 @@ public class ControlFlowUtil { } if (gotoOffset >= end || gotoOffset < start) { processGotoStatement(classesFilter, exitStatements, statement); - } else { + } + else { boolean isReturn = instruction instanceof GoToInstruction && ((GoToInstruction)instruction).isReturn; final Instruction gotoInstruction = flow.getInstructions().get(gotoOffset); isReturn |= gotoInstruction instanceof GoToInstruction && ((GoToInstruction)gotoInstruction).isReturn; @@ -357,7 +369,7 @@ public class ControlFlowUtil { return offset; } - public static final Class[] DEFAULT_EXIT_STATEMENTS_CLASSES = new Class[] {PsiReturnStatement.class, PsiBreakStatement.class, PsiContinueStatement.class}; + public static final Class[] DEFAULT_EXIT_STATEMENTS_CLASSES = new Class[]{PsiReturnStatement.class, PsiBreakStatement.class, PsiContinueStatement.class}; private static PsiStatement findStatement(ControlFlow flow, int offset) { PsiElement element = flow.getElement(offset); @@ -401,22 +413,23 @@ public class ControlFlowUtil { /** * Checks possibility of extracting code fragment outside containing anonymous (local) class. * Also collects variables to be passed as additional parameters. - * @return true if code fragement can be extracted outside - * @param array Vector to collect variables to be passed as additional parameters - * @param scope scope to be scanned (part of code fragement to be extracted) - * @param member member containing the code to be extracted + * + * @param array Vector to collect variables to be passed as additional parameters + * @param scope scope to be scanned (part of code fragement to be extracted) + * @param member member containing the code to be extracted * @param targetClassMember member in target class containing code fragement + * @return true if code fragement can be extracted outside */ public static boolean collectOuterLocals(List array, PsiElement scope, PsiElement member, PsiElement targetClassMember) { if (scope instanceof PsiMethodCallExpression) { final PsiMethodCallExpression call = (PsiMethodCallExpression)scope; - if (!checkReferenceExpressionScope (call.getMethodExpression(), targetClassMember)) { + if (!checkReferenceExpressionScope(call.getMethodExpression(), targetClassMember)) { return false; } } else if (scope instanceof PsiReferenceExpression) { - if (!checkReferenceExpressionScope ((PsiReferenceExpression)scope, targetClassMember)) { + if (!checkReferenceExpressionScope((PsiReferenceExpression)scope, targetClassMember)) { return false; } } @@ -483,10 +496,10 @@ public class ControlFlowUtil { depthFirstSearch(flow, visitor); return visitor.getResult().booleanValue(); } - + public static boolean processReturns(final ControlFlow flow, final ReturnStatementsVisitor afterVisitor) throws IncorrectOperationException { final ConvertReturnClientVisitor instructionsVisitor = new ConvertReturnClientVisitor(flow, afterVisitor); - + depthFirstSearch(flow, instructionsVisitor); instructionsVisitor.afterProcessing(); @@ -510,7 +523,7 @@ public class ControlFlowUtil { if (instruction.isReturn) { final PsiElement element = myFlow.getElement(offset); if (element instanceof PsiReturnStatement) { - final PsiReturnStatement returnStatement = (PsiReturnStatement) element; + final PsiReturnStatement returnStatement = (PsiReturnStatement)element; myAffectedReturns.add(returnStatement); } } @@ -532,26 +545,30 @@ public class ControlFlowUtil { isNormalCompletion[myFlow.getSize()] = true; } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); boolean isNormal = instruction.offset == nextOffset && nextOffset != offset + 1 ? - !isLeaf(nextOffset) && isNormalCompletion[nextOffset] : - isLeaf(nextOffset) || isNormalCompletion[nextOffset]; + !isLeaf(nextOffset) && isNormalCompletion[nextOffset] : + isLeaf(nextOffset) || isNormalCompletion[nextOffset]; isNormalCompletion[offset] |= isNormal; } - @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); isNormalCompletion[offset] |= !isLeaf(nextOffset) && isNormalCompletion[nextOffset]; } - @Override public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); isNormalCompletion[offset] |= !instruction.isReturn && isNormalCompletion[nextOffset]; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); boolean isNormal = isLeaf(nextOffset) || isNormalCompletion[nextOffset]; @@ -580,7 +597,8 @@ public class ControlFlowUtil { } } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; int throwToOffset = instruction.offset; @@ -599,7 +617,8 @@ public class ControlFlowUtil { isNormalCompletion[offset] |= isNormal; } - @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset <= endOffset) { @@ -608,7 +627,8 @@ public class ControlFlowUtil { } } - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset > endOffset && nextOffset != offset + 1) { @@ -618,15 +638,17 @@ public class ControlFlowUtil { isNormalCompletion[offset] |= isNormal; } - @Override public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; - boolean isRethrowFromFinally = instruction instanceof ReturnInstruction && ((ReturnInstruction) instruction).isRethrowFromFinally(); + boolean isRethrowFromFinally = instruction instanceof ReturnInstruction && ((ReturnInstruction)instruction).isRethrowFromFinally(); boolean isNormal = !instruction.isReturn && isNormalCompletion[nextOffset] && !isRethrowFromFinally; isNormalCompletion[offset] |= isNormal; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; final boolean isNormal = isLeaf(nextOffset) || isNormalCompletion[nextOffset]; @@ -647,7 +669,7 @@ public class ControlFlowUtil { InstructionClientVisitor[] visitors = new InstructionClientVisitor[]{ new ReturnPresentClientVisitor(flow), new UnreachableStatementClientVisitor(flow), - new ReadBeforeWriteClientVisitor(flow), + new ReadBeforeWriteClientVisitor(flow, true), new InitializedTwiceClientVisitor(flow, 0), }; CompositeInstructionClientVisitor visitor = new CompositeInstructionClientVisitor(visitors); @@ -664,10 +686,13 @@ public class ControlFlowUtil { // false if control flow at this offset terminates abruptly final boolean[] canCompleteNormally = new boolean[flow.getSize() + 1]; - @Override public void visitConditionalGoToInstruction(ConditionalGoToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalGoToInstruction(ConditionalGoToInstruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, false); } - @Override public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { + + @Override + public void visitGoToInstruction(GoToInstruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, instruction.isReturn); } @@ -684,7 +709,8 @@ public class ControlFlowUtil { canCompleteNormally[offset] |= isNormal; } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; int throwToOffset = instruction.offset; @@ -698,7 +724,8 @@ public class ControlFlowUtil { canCompleteNormally[offset] |= isNormal; } - @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset <= endOffset) { @@ -707,7 +734,8 @@ public class ControlFlowUtil { } } - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (offset > endOffset) return; if (nextOffset > endOffset && nextOffset != offset + 1) { @@ -717,7 +745,8 @@ public class ControlFlowUtil { canCompleteNormally[offset] |= isNormal; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { checkInstruction(offset, nextOffset, false); } @@ -739,6 +768,7 @@ public class ControlFlowUtil { depthFirstSearch(flow, visitor); return visitor.getResult(); } + private static class UnreachableStatementClientVisitor extends InstructionClientVisitor { private final ControlFlow myFlow; @@ -760,7 +790,7 @@ public class ControlFlowUtil { } if (element instanceof PsiStatement && element.getParent() instanceof PsiForStatement - && element == ((PsiForStatement) element.getParent()).getUpdate()) { + && element == ((PsiForStatement)element.getParent()).getUpdate()) { continue; } //filter out generated stmts @@ -809,11 +839,13 @@ public class ControlFlowUtil { class MyVisitor extends InstructionClientVisitor { // true if from this point below there may be branch with no variable assignment final boolean[] maybeUnassigned = new boolean[flow.getSize() + 1]; + { - maybeUnassigned[maybeUnassigned.length-1] = true; + maybeUnassigned[maybeUnassigned.length - 1] = true; } - @Override public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { + @Override + public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { if (instruction.variable == variable) { maybeUnassigned[offset] = false; } @@ -822,7 +854,8 @@ public class ControlFlowUtil { } } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean unassigned = offset == flow.getSize() - 1 || !isLeaf(nextOffset) && maybeUnassigned[nextOffset]; @@ -830,21 +863,24 @@ public class ControlFlowUtil { maybeUnassigned[offset] |= unassigned; } - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { visitInstruction(instruction, offset, nextOffset); // clear return statements after procedure as well - for (int i = instruction.procBegin; i flow.getSize()) nextOffset = flow.getSize(); boolean unassigned = !isLeaf(nextOffset) && maybeUnassigned[nextOffset]; maybeUnassigned[offset] |= unassigned; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean unassigned = isLeaf(nextOffset) || maybeUnassigned[nextOffset]; @@ -867,27 +903,31 @@ public class ControlFlowUtil { // true if from this point below there may be branch with variable assignment final boolean[] maybeAssigned = new boolean[flow.getSize() + 1]; - @Override public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { + @Override + public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean assigned = instruction.variable == variable || maybeAssigned[nextOffset]; maybeAssigned[offset] |= assigned; } - @Override public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitThrowToInstruction(ThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean assigned = !isLeaf(nextOffset) && maybeAssigned[nextOffset]; maybeAssigned[offset] |= assigned; } - @Override public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalThrowToInstruction(ConditionalThrowToInstruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); int throwToOffset = instruction.offset; boolean assigned = throwToOffset == nextOffset ? !isLeaf(nextOffset) && maybeAssigned[nextOffset] : - maybeAssigned[nextOffset]; + maybeAssigned[nextOffset]; maybeAssigned[offset] |= assigned; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); boolean assigned = maybeAssigned[nextOffset]; @@ -914,7 +954,8 @@ public class ControlFlowUtil { // set of exit posint reached from this offset final TIntHashSet[] exitPoints = new TIntHashSet[flow.getSize()]; - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset > flow.getSize()) nextOffset = flow.getSize(); if (exitPoints[offset] == null) { @@ -978,7 +1019,8 @@ public class ControlFlowUtil { synchronized (instructions) { final IntArrayList currentProcedureReturnOffsets = new IntArrayList(); ControlFlowInstructionVisitor getNextOffsetVisitor = new ControlFlowInstructionVisitor() { - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { instruction.execute(offset + 1); int newOffset = instruction.offset; // 'procedure' pointed by call instruction should be processed regardless of whether it was already visited or not @@ -997,7 +1039,8 @@ public class ControlFlowUtil { currentProcedureReturnOffsets.add(offset + 1); } - @Override public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) { + @Override + public void visitReturnInstruction(ReturnInstruction instruction, int offset, int nextOffset) { int newOffset = instruction.execute(false); if (newOffset != -1) { oldOffsets.add(offset); @@ -1008,7 +1051,8 @@ public class ControlFlowUtil { } } - @Override public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) { + @Override + public void visitBranchingInstruction(BranchingInstruction instruction, int offset, int nextOffset) { int newOffset = instruction.offset; oldOffsets.add(offset); newOffsets.add(newOffset); @@ -1017,7 +1061,8 @@ public class ControlFlowUtil { newOffsets.add(-1); } - @Override public void visitConditionalBranchingInstruction(ConditionalBranchingInstruction instruction, int offset, int nextOffset) { + @Override + public void visitConditionalBranchingInstruction(ConditionalBranchingInstruction instruction, int offset, int nextOffset) { int newOffset = instruction.offset; oldOffsets.add(offset); @@ -1033,7 +1078,8 @@ public class ControlFlowUtil { newOffsets.add(-1); } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { int newOffset = offset + 1; oldOffsets.add(offset); newOffsets.add(newOffset); @@ -1063,7 +1109,7 @@ public class ControlFlowUtil { } if (!currentProcedureReturnOffsets.isEmpty()) { int returnOffset = currentProcedureReturnOffsets.get(currentProcedureReturnOffsets.size() - 1); - CallInstruction callInstruction = (CallInstruction) instructions.get(returnOffset - 1); + CallInstruction callInstruction = (CallInstruction)instructions.get(returnOffset - 1); // check if we inside procedure but 'return offset' stack is empty, so // we should push back to 'return offset' stack synchronized (callInstruction.stack) { @@ -1099,6 +1145,7 @@ public class ControlFlowUtil { newList.list.add(value); return newList; } + public CopyOnWriteList remove(VariableInfo value) { CopyOnWriteList newList = new CopyOnWriteList(); List list = getList(); @@ -1116,8 +1163,17 @@ public class ControlFlowUtil { } public CopyOnWriteList() { - list = new LinkedList(); + this(Collections.emptyList()); } + + public CopyOnWriteList(VariableInfo... infos) { + this(Arrays.asList(infos)); + } + + public CopyOnWriteList(Collection infos) { + list = new LinkedList(infos); + } + public CopyOnWriteList addAll(CopyOnWriteList addList) { CopyOnWriteList newList = new CopyOnWriteList(); List list = getList(); @@ -1133,7 +1189,12 @@ public class ControlFlowUtil { } return newList; } + + public static CopyOnWriteList add(@Nullable CopyOnWriteList list, @NotNull VariableInfo value) { + return list == null ? new CopyOnWriteList(value) : list.add(value); + } } + public static class VariableInfo { private final PsiVariable variable; public final PsiElement expression; @@ -1151,68 +1212,81 @@ public class ControlFlowUtil { return variable.hashCode(); } } - private static void merge(int offset, CopyOnWriteList readVars, CopyOnWriteList[] readVariables) { - if (readVars != null) { - CopyOnWriteList existing = readVariables[offset]; - readVariables[offset] = existing == null ? readVars : existing.addAll(readVars); + + private static void merge(int offset, CopyOnWriteList source, CopyOnWriteList[] target) { + if (source != null) { + CopyOnWriteList existing = target[offset]; + target[offset] = existing == null ? source : existing.addAll(source); } } + /** - * @return list of PsiReferenceExpression of usages of non-initialized variables + * @return list of PsiReferenceExpression of usages of non-initialized local variables */ - public static List getReadBeforeWrite(final ControlFlow flow) { - InstructionClientVisitor> visitor = new ReadBeforeWriteClientVisitor(flow); + public static List getReadBeforeWriteLocals(ControlFlow flow) { + final InstructionClientVisitor> visitor = new ReadBeforeWriteClientVisitor(flow, true); depthFirstSearch(flow, visitor); return visitor.getResult(); } + + public static List getReadBeforeWrite(ControlFlow flow) { + final InstructionClientVisitor> visitor = new ReadBeforeWriteClientVisitor(flow, false); + depthFirstSearch(flow, visitor); + return visitor.getResult(); + } + private static class ReadBeforeWriteClientVisitor extends InstructionClientVisitor> { // map of variable->PsiReferenceExpressions for all read before written variables for this point and below in control flow private final CopyOnWriteList[] readVariables; private final ControlFlow myFlow; + private boolean localVariablesOnly; - public ReadBeforeWriteClientVisitor(ControlFlow flow) { + public ReadBeforeWriteClientVisitor(ControlFlow flow, boolean localVariablesOnly) { myFlow = flow; - readVariables = new CopyOnWriteList[myFlow.getSize()+1]; + this.localVariablesOnly = localVariablesOnly; + readVariables = new CopyOnWriteList[myFlow.getSize() + 1]; } - @Override public void visitReadVariableInstruction(ReadVariableInstruction instruction, int offset, int nextOffset) { - if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); - CopyOnWriteList readVars = readVariables[nextOffset]; - PsiElement element = myFlow.getElement(offset); + @Override + public void visitReadVariableInstruction(ReadVariableInstruction instruction, int offset, int nextOffset) { + CopyOnWriteList readVars = readVariables[Math.min(nextOffset, myFlow.getSize())]; final PsiVariable variable = instruction.variable; - if (!(variable instanceof PsiParameter) || ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) { - PsiReferenceExpression expression = getEnclosingReferenceExpression(element, variable); + if (!localVariablesOnly || !isMethodParameter(variable)) { + final PsiReferenceExpression expression = getEnclosingReferenceExpression(myFlow.getElement(offset), variable); if (expression != null) { - VariableInfo variableInfo = new VariableInfo(variable, expression); - if (readVars == null) { - readVars = new CopyOnWriteList(); - readVars.list.add(variableInfo); - } - else { - readVars = readVars.add(variableInfo); - } + readVars = CopyOnWriteList.add(readVars, new VariableInfo(variable, expression)); } } merge(offset, readVars, readVariables); } - @Override public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { - if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); - CopyOnWriteList readVars = readVariables[nextOffset]; + @Override + public void visitWriteVariableInstruction(WriteVariableInstruction instruction, int offset, int nextOffset) { + CopyOnWriteList readVars = readVariables[Math.min(nextOffset, myFlow.getSize())]; + if (readVars == null) return; + final PsiVariable variable = instruction.variable; - if (readVars != null && (!(variable instanceof PsiParameter) || ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement)) { + if (!localVariablesOnly || !isMethodParameter(variable)) { readVars = readVars.remove(new VariableInfo(variable, null)); } merge(offset, readVars, readVariables); } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { - if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); - CopyOnWriteList readVars = readVariables[nextOffset]; - merge(offset, readVars, readVariables); + private static boolean isMethodParameter(@NotNull PsiVariable variable) { + if (variable instanceof PsiParameter) { + final PsiParameter parameter = (PsiParameter)variable; + return !(parameter.getDeclarationScope() instanceof PsiForeachStatement); + } + return false; } - @Override public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + merge(offset, readVariables[Math.min(nextOffset, myFlow.getSize())], readVariables); + } + + @Override + public void visitCallInstruction(CallInstruction instruction, int offset, int nextOffset) { visitInstruction(instruction, offset, nextOffset); for (int i = instruction.procBegin; i <= instruction.procEnd; i++) { readVariables[i] = null; @@ -1221,30 +1295,32 @@ public class ControlFlowUtil { @Override public List getResult() { - List problemsFound = new ArrayList(); - CopyOnWriteList topReadVariables = readVariables[0]; - if (topReadVariables != null) { - List list = topReadVariables.getList(); - for (final VariableInfo variableInfo : list) { - problemsFound.add((PsiReferenceExpression)variableInfo.expression); - } + final CopyOnWriteList topReadVariables = readVariables[0]; + if (topReadVariables == null) return Collections.emptyList(); + + final List result = new ArrayList(); + List list = topReadVariables.getList(); + for (final VariableInfo variableInfo : list) { + result.add((PsiReferenceExpression)variableInfo.expression); } - return problemsFound; + return result; } } public static final int NORMAL_COMPLETION_REASON = 1; public static final int RETURN_COMPLETION_REASON = 2; + /** * return reasons.normalCompletion when block can complete normally - * reasons.returnCalled when block can complete abruptly because of return statement executed + * reasons.returnCalled when block can complete abruptly because of return statement executed */ public static int getCompletionReasons(final ControlFlow flow, final int offset, final int endOffset) { class MyVisitor extends InstructionClientVisitor { final boolean[] normalCompletion = new boolean[endOffset]; final boolean[] returnCalled = new boolean[endOffset]; - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { boolean ret = nextOffset < endOffset && returnCalled[nextOffset]; boolean normal = nextOffset < endOffset && normalCompletion[nextOffset]; final PsiElement element = flow.getElement(offset); @@ -1302,62 +1378,63 @@ public class ControlFlowUtil { writtenTwiceVariables = new CopyOnWriteList[myFlow.getSize() + 1]; } - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { - if (nextOffset > myFlow.getSize()) nextOffset = myFlow.getSize(); + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + final int safeNextOffset = Math.min(nextOffset, myFlow.getSize()); - CopyOnWriteList writeVars = writtenVariables[nextOffset]; - CopyOnWriteList writeTwiceVars = writtenTwiceVariables[nextOffset]; + CopyOnWriteList writeVars = writtenVariables[safeNextOffset]; + CopyOnWriteList writeTwiceVars = writtenTwiceVariables[safeNextOffset]; if (instruction instanceof WriteVariableInstruction) { - final WriteVariableInstruction writeVariableInstruction = (WriteVariableInstruction)instruction; - final PsiVariable variable = writeVariableInstruction.variable; - final PsiElement element = myFlow.getElement(offset); + final PsiVariable variable = ((WriteVariableInstruction)instruction).variable; + + final PsiElement latestWriteVarExpression = getLatestWriteVarExpression(writeVars, variable); - PsiElement latestWriteVarExpression = null; - if (writeVars != null) { - List list = writeVars.getList(); - for (final VariableInfo variableInfo : list) { - if (variableInfo.variable == variable) { - latestWriteVarExpression = variableInfo.expression; - break; - } - } - } if (latestWriteVarExpression == null) { - PsiElement expression = null; - if (element instanceof PsiAssignmentExpression - && ((PsiAssignmentExpression)element).getLExpression() instanceof PsiReferenceExpression) { - expression = ((PsiAssignmentExpression)element).getLExpression(); - } - else if (element instanceof PsiPostfixExpression) { - expression = ((PsiPostfixExpression)element).getOperand(); - } - else if (element instanceof PsiPrefixExpression) { - expression = ((PsiPrefixExpression)element).getOperand(); - } - else if (element instanceof PsiDeclarationStatement) { - //should not happen - expression = element; - } - if (writeVars == null) { - writeVars = new CopyOnWriteList(); - } - writeVars = writeVars.add(new VariableInfo(variable, expression)); + final PsiElement expression = getExpression(myFlow.getElement(offset)); + writeVars = CopyOnWriteList.add(writeVars, new VariableInfo(variable, expression)); } else { - if (writeTwiceVars == null) { - writeTwiceVars = new CopyOnWriteList(); - } - writeTwiceVars = writeTwiceVars.add(new VariableInfo(variable, latestWriteVarExpression)); + writeTwiceVars = CopyOnWriteList.add(writeTwiceVars, new VariableInfo(variable, latestWriteVarExpression)); } } merge(offset, writeVars, writtenVariables); merge(offset, writeTwiceVars, writtenTwiceVariables); } + @Nullable + private static PsiElement getExpression(@NotNull PsiElement element) { + if (element instanceof PsiAssignmentExpression && ((PsiAssignmentExpression)element).getLExpression() instanceof PsiReferenceExpression) { + return ((PsiAssignmentExpression)element).getLExpression(); + } + else if (element instanceof PsiPostfixExpression) { + return ((PsiPostfixExpression)element).getOperand(); + } + else if (element instanceof PsiPrefixExpression) { + return ((PsiPrefixExpression)element).getOperand(); + } + else if (element instanceof PsiDeclarationStatement) { + //should not happen + return element; + } + return null; + } + + @Nullable + private static PsiElement getLatestWriteVarExpression(@Nullable CopyOnWriteList writeVars, @Nullable PsiVariable variable) { + if (writeVars == null) return null; + + for (final VariableInfo variableInfo : writeVars.getList()) { + if (variableInfo.variable == variable) { + return variableInfo.expression; + } + } + return null; + } + @Override @NotNull public Collection getResult() { - CopyOnWriteList writtenTwiceVariable = writtenTwiceVariables[myStartOffset]; + final CopyOnWriteList writtenTwiceVariable = writtenTwiceVariables[myStartOffset]; if (writtenTwiceVariable == null) return Collections.emptyList(); return writtenTwiceVariable.getList(); } @@ -1370,7 +1447,8 @@ public class ControlFlowUtil { class MyVisitor extends InstructionClientVisitor { boolean reachable; - @Override public void visitInstruction(Instruction instruction, int offset, int nextOffset) { + @Override + public void visitInstruction(Instruction instruction, int offset, int nextOffset) { if (nextOffset == instructionOffset) reachable = true; } @@ -1410,5 +1488,4 @@ public class ControlFlowUtil { int startOffset = flow.getStartOffset(assignmentExpression); return startOffset != -1 && isInstructionReachable(flow, startOffset, startOffset); } -} - +} \ No newline at end of file diff --git a/java/java-tests/testData/core/loadingTest/.idea/.name b/java/java-tests/testData/core/loadingTest/.idea/.name new file mode 100644 index 000000000000..eecda08ff4d4 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/.name @@ -0,0 +1 @@ +loadingTest \ No newline at end of file diff --git a/java/java-tests/testData/core/loadingTest/.idea/compiler.xml b/java/java-tests/testData/core/loadingTest/.idea/compiler.xml new file mode 100644 index 000000000000..a1b41c52c724 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/compiler.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/copyright/profiles_settings.xml b/java/java-tests/testData/core/loadingTest/.idea/copyright/profiles_settings.xml new file mode 100644 index 000000000000..3572571ad83c --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/java/java-tests/testData/core/loadingTest/.idea/encodings.xml b/java/java-tests/testData/core/loadingTest/.idea/encodings.xml new file mode 100644 index 000000000000..e206d70d8595 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/libraries/annotations.xml b/java/java-tests/testData/core/loadingTest/.idea/libraries/annotations.xml new file mode 100644 index 000000000000..09db609fa3db --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/libraries/annotations.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/java/java-tests/testData/core/loadingTest/.idea/misc.xml b/java/java-tests/testData/core/loadingTest/.idea/misc.xml new file mode 100644 index 000000000000..f898e64a705f --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/misc.xml @@ -0,0 +1,79 @@ + + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + + + + + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/modules.xml b/java/java-tests/testData/core/loadingTest/.idea/modules.xml new file mode 100644 index 000000000000..2cc724a23410 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/scopes/scope_settings.xml b/java/java-tests/testData/core/loadingTest/.idea/scopes/scope_settings.xml new file mode 100644 index 000000000000..922003b8433b --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/java/java-tests/testData/core/loadingTest/.idea/uiDesigner.xml b/java/java-tests/testData/core/loadingTest/.idea/uiDesigner.xml new file mode 100644 index 000000000000..3b0002030884 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/vcs.xml b/java/java-tests/testData/core/loadingTest/.idea/vcs.xml new file mode 100644 index 000000000000..def6a6a18457 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/.idea/workspace.xml b/java/java-tests/testData/core/loadingTest/.idea/workspace.xml new file mode 100644 index 000000000000..29e67f695103 --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/.idea/workspace.xml @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + + + + + + 1337359306662 + 1337359306662 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No facets are configured + + + + + + + + acts-as-taggable-on (v2.0.6, ruby-1.8.7-p334) [gem] + + + + + + + + 1.6 + + + + + + + + loadingTest + + + + + + + + 1.6 + + + + + + + + annotations + + + + + + + + + diff --git a/java/java-tests/testData/core/loadingTest/annotations.jar b/java/java-tests/testData/core/loadingTest/annotations.jar new file mode 100644 index 000000000000..d3ae4abf004d Binary files /dev/null and b/java/java-tests/testData/core/loadingTest/annotations.jar differ diff --git a/java/java-tests/testData/core/loadingTest/loadingTest.iml b/java/java-tests/testData/core/loadingTest/loadingTest.iml new file mode 100644 index 000000000000..0c53580e201f --- /dev/null +++ b/java/java-tests/testData/core/loadingTest/loadingTest.iml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/for/expected.xml b/java/java-tests/testData/inspection/parameterCanBeLocal/for/expected.xml new file mode 100644 index 000000000000..ecdf1549b564 --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/for/expected.xml @@ -0,0 +1,8 @@ + + + + Test.java + 2 + Parameter can be converted to a variable + + diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/for/src/Test.java b/java/java-tests/testData/inspection/parameterCanBeLocal/for/src/Test.java new file mode 100644 index 000000000000..95467a612c6d --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/for/src/Test.java @@ -0,0 +1,8 @@ +class Temp { + public Temp(int p) { + for (int i = 0; i < 10; i++) { + p = i; + System.out.print(p); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/if/expected.xml b/java/java-tests/testData/inspection/parameterCanBeLocal/if/expected.xml new file mode 100644 index 000000000000..06abec6d7bd7 --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/if/expected.xml @@ -0,0 +1,8 @@ + + + + Test.java + 4 + Parameter can be converted to a variable + + diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/if/src/Test.java b/java/java-tests/testData/inspection/parameterCanBeLocal/if/src/Test.java new file mode 100644 index 000000000000..4ae6800d5079 --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/if/src/Test.java @@ -0,0 +1,13 @@ +class Temp { + public boolean flag; + + void test(int p) { + if (flag) { + p = 1; + } + else { + p = 2; + } + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/simple/expected.xml b/java/java-tests/testData/inspection/parameterCanBeLocal/simple/expected.xml new file mode 100644 index 000000000000..a83abd288af9 --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/simple/expected.xml @@ -0,0 +1,8 @@ + + + + Test.java + 3 + Parameter can be converted to a variable + + diff --git a/java/java-tests/testData/inspection/parameterCanBeLocal/simple/src/Test.java b/java/java-tests/testData/inspection/parameterCanBeLocal/simple/src/Test.java new file mode 100644 index 000000000000..33ec47a32bfa --- /dev/null +++ b/java/java-tests/testData/inspection/parameterCanBeLocal/simple/src/Test.java @@ -0,0 +1,7 @@ +class Temp { + + void test(int p) { + p = 1; + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java new file mode 100644 index 000000000000..ce8711eb6de5 --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java @@ -0,0 +1,9 @@ +// "Convert to local variable" "true" +class Temp { + public Temp() { + for (int i = 0; i < 10; i++) { + int p = i; + System.out.print(p); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java new file mode 100644 index 000000000000..e6d8f7518700 --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java @@ -0,0 +1,15 @@ +// "Convert to local variable" "true" +class Temp { + public boolean flag; + + void test() { + int p; + if (flag) { + p = 1; + } + else { + p = 2; + } + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java new file mode 100644 index 000000000000..f692ff1cafbc --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java @@ -0,0 +1,8 @@ +// "Convert to local variable" "true" +class Temp { + + void test() { + int p = 1; + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeFor.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeFor.java new file mode 100644 index 000000000000..598b23780897 --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeFor.java @@ -0,0 +1,9 @@ +// "Convert to local variable" "true" +class Temp { + public Temp(int p) { + for (int i = 0; i < 10; i++) { + p = i; + System.out.print(p); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeIf.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeIf.java new file mode 100644 index 000000000000..6dc3bb16c1ac --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeIf.java @@ -0,0 +1,14 @@ +// "Convert to local variable" "true" +class Temp { + public boolean flag; + + void test(int p) { + if (flag) { + p = 1; + } + else { + p = 2; + } + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeSimple.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeSimple.java new file mode 100644 index 000000000000..cf03ce27246c --- /dev/null +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/beforeSimple.java @@ -0,0 +1,8 @@ +// "Convert to local variable" "true" +class Temp { + + void test(int p) { + p = 1; + System.out.print(p); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java new file mode 100644 index 000000000000..fc3eddbb1b9c --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java @@ -0,0 +1,26 @@ +public class Demo { + + static class MyParent { + private final String value; + + MyParent(String value) { + this.value = value; + } + } + + static class MyChild extends MyParent { + MyChild(String value) { + super(value); + } + } + + public static void main(String[] args) { + + String value = "something"; + final MyParent p; + if (true) + p = new MyChild(value); + else + p = new MyParent("value"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after new file mode 100644 index 000000000000..8a2d39edbd07 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after @@ -0,0 +1,22 @@ +public class Demo { + + static class MyParent { + private final String value; + + MyParent(String value) { + this.value = value; + } + } + + public static void main(String[] args) { + + String value = "something"; + final MyParent p; + if (true) { + final String value1 = value; + p = new MyParent(value1); + } + else + p = new MyParent("value"); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ConvertParameterToLocalVariableTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/ConvertParameterToLocalVariableTest.java new file mode 100644 index 000000000000..23d9c037a6a4 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ConvertParameterToLocalVariableTest.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/* + * User: anna + * Date: 16-May-2007 + */ +package com.intellij.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; +import com.intellij.codeInspection.varScopeCanBeNarrowed.ParameterCanBeLocalInspection; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NonNls; + +public class ConvertParameterToLocalVariableTest extends LightQuickFixTestCase { + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection"; + } + + public void test() throws Exception { + doAllTests(); + } + + @Override + protected void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath, final String testName) + throws Exception { + + final LocalQuickFix fix = new ParameterCanBeLocalInspection.ConvertParameterToLocalQuickFix(); + final int offset = getEditor().getCaretModel().getOffset(); + final PsiElement psiElement = getFile().findElementAt(offset); + assert psiElement != null; + final InspectionManager manager = InspectionManager.getInstance(getProject()); + final ProblemDescriptor descriptor = manager.createProblemDescriptor(psiElement, "", fix, ProblemHighlightType.LIKE_UNUSED_SYMBOL, true); + fix.applyFix(getProject(), descriptor); + final String expectedFilePath = getBasePath() + "/after" + testName; + checkResultByFile("In file :" + expectedFilePath, expectedFilePath, false); + } + + + @Override + @NonNls + protected String getBasePath() { + return "/quickFix/ConvertParameterToLocalVariable"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ParameterCanBeLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/ParameterCanBeLocalTest.java new file mode 100644 index 000000000000..10cc1f0f570f --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ParameterCanBeLocalTest.java @@ -0,0 +1,36 @@ +/* + * 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.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection; +import com.intellij.codeInspection.varScopeCanBeNarrowed.ParameterCanBeLocalInspection; +import com.intellij.testFramework.InspectionTestCase; + +public class ParameterCanBeLocalTest extends InspectionTestCase { + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection"; + } + + private void doTest() throws Exception { + doTest("parameterCanBeLocal/" + getTestName(true), new ParameterCanBeLocalInspection()); + } + + public void testSimple () throws Exception { doTest(); } + public void testIf () throws Exception { doTest(); } + public void testFor () throws Exception { doTest(); } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java index f9edb4b24490..469acd2a150f 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java @@ -226,6 +226,10 @@ public class InlineToAnonymousClassTest extends LightRefactoringTestCase { doTest(false, true); } + public void testBraces() throws Exception { + doTest(false, false); + } + public void testNoInlineAbstract() throws Exception { doTestNoInline("Abstract classes cannot be inlined"); } diff --git a/platform/core-api/src/com/intellij/openapi/application/Application.java b/platform/core-api/src/com/intellij/openapi/application/Application.java index 78c74cf74b3e..f14d3344675a 100644 --- a/platform/core-api/src/com/intellij/openapi/application/Application.java +++ b/platform/core-api/src/com/intellij/openapi/application/Application.java @@ -324,11 +324,13 @@ public interface Application extends ComponentManager { boolean isActive(); /** + * @deprecated use {@link #runReadAction(Runnable)} instead * Returns lock used for read operations, should be closed in finally block */ AccessToken acquireReadActionLock(); /** + * @deprecated use {@link #runWriteAction(Runnable)} instead * Returns lock used for write operations, should be closed in finally block */ AccessToken acquireWriteActionLock(@Nullable Class marker); diff --git a/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java b/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java new file mode 100644 index 000000000000..f539a84ae79a --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java @@ -0,0 +1,26 @@ +/* + * 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.openapi.components; + +import org.jetbrains.annotations.NonNls; + +/** + * @author yole + */ +public class ExtensionAreas { + @NonNls public static final String IDEA_PROJECT = "IDEA_PROJECT"; + @NonNls public static final String IDEA_MODULE = "IDEA_MODULE"; +} diff --git a/platform/core-api/src/com/intellij/openapi/vfs/JarCopyingFileSystem.java b/platform/core-api/src/com/intellij/openapi/vfs/JarCopyingFileSystem.java new file mode 100644 index 000000000000..768884a2194e --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/vfs/JarCopyingFileSystem.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vfs; + +/** + * @author yole + */ +public interface JarCopyingFileSystem { + void setNoCopyJarForPath(String pathInJar); +} diff --git a/platform/core-api/src/com/intellij/openapi/vfs/StandardFileSystems.java b/platform/core-api/src/com/intellij/openapi/vfs/StandardFileSystems.java index 9eff7c733dec..9ba0bff13b85 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/StandardFileSystems.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/StandardFileSystems.java @@ -28,6 +28,7 @@ public class StandardFileSystems { public static String FILE_PROTOCOL = "file"; public static String JAR_PROTOCOL = "jar"; public static String JAR_SEPARATOR = "!/"; + public static String HTTP_PROTOCOL = "http"; private static final NotNullLazyValue ourLocal = new NotNullLazyValue() { @NotNull diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java index 4e84b94aab7e..b8d501cd705b 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java @@ -222,4 +222,9 @@ public class VfsUtilCore { public static File virtualToIoFile(@NotNull VirtualFile file) { return new File(PathUtil.toPresentableUrl(file.getUrl())); } + + @NotNull + public static String pathToUrl(@NonNls @NotNull String path) { + return VirtualFileManager.constructUrl(StandardFileSystems.FILE_PROTOCOL, path); + } } diff --git a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java index 19ef4406fc54..ce5ed1b160b6 100644 --- a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java @@ -21,6 +21,7 @@ import com.intellij.mock.*; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.extensions.ExtensionPoint; @@ -97,7 +98,7 @@ public class CoreEnvironment { myLocalFileSystem = new CoreLocalFileSystem(); myJarFileSystem = new CoreJarFileSystem(); - Extensions.registerAreaClass("IDEA_PROJECT", null); + Extensions.registerAreaClass(ExtensionAreas.IDEA_PROJECT, null); myProject = new MockProject(myApplication.getPicoContainer(), myParentDisposable); final MutablePicoContainer appContainer = myApplication.getPicoContainer(); @@ -131,11 +132,10 @@ public class CoreEnvironment { myApplication.registerService(StubTreeLoader.class, new CoreStubTreeLoader()); myApplication.registerService(PsiReferenceService.class, new PsiReferenceServiceImpl()); - registerExtensionPoint(Extensions.getRootArea(), ContentBasedFileSubstitutor.EP_NAME, ContentBasedFileSubstitutor.class); + registerApplicationExtensionPoint(ContentBasedFileSubstitutor.EP_NAME, ContentBasedFileSubstitutor.class); registerExtensionPoint(Extensions.getRootArea(), BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class); myFileIndexFacade = new MockFileIndexFacade(myProject); - final MutablePicoContainer projectContainer = myProject.getPicoContainer(); PsiModificationTrackerImpl modificationTracker = new PsiModificationTrackerImpl(myProject); myProject.registerService(PsiModificationTracker.class, modificationTracker); @@ -175,6 +175,10 @@ public class CoreEnvironment { }; } + public MockApplication getApplication() { + return myApplication; + } + public Disposable getParentDisposable() { return myParentDisposable; } @@ -199,7 +203,7 @@ public class CoreEnvironment { addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition); } - protected void registerComponentInstance(final MutablePicoContainer container, final Class key, final T implementation) { + public static void registerComponentInstance(final MutablePicoContainer container, final Class key, final T implementation) { container.unregisterComponent(key); container.registerComponentInstance(key, implementation); } @@ -235,20 +239,25 @@ public class CoreEnvironment { }); } - protected void registerExtensionPoint(final ExtensionsArea area, final ExtensionPointName extensionPointName, - final Class aClass) { + public static void registerExtensionPoint(final ExtensionsArea area, final ExtensionPointName extensionPointName, + final Class aClass) { final String name = extensionPointName.getName(); registerExtensionPoint(area, name, aClass); } - protected void registerExtensionPoint(ExtensionsArea area, String name, Class aClass) { + public static void registerExtensionPoint(ExtensionsArea area, String name, Class aClass) { if (!area.hasExtensionPoint(name)) { ExtensionPoint.Kind kind = aClass.isInterface() || (aClass.getModifiers() & Modifier.ABSTRACT) != 0 ? ExtensionPoint.Kind.INTERFACE : ExtensionPoint.Kind.BEAN_CLASS; area.registerExtensionPoint(name, aClass.getName(), kind); } } - protected void registerProjectExtensionPoint(final ExtensionPointName extensionPointName, + public static void registerApplicationExtensionPoint(final ExtensionPointName extensionPointName, final Class aClass) { + final String name = extensionPointName.getName(); + registerExtensionPoint(Extensions.getRootArea(), name, aClass); + } + + public void registerProjectExtensionPoint(final ExtensionPointName extensionPointName, final Class aClass) { registerExtensionPoint(Extensions.getArea(myProject), extensionPointName, aClass); } diff --git a/platform/core-impl/src/com/intellij/mock/MockProject.java b/platform/core-impl/src/com/intellij/mock/MockProject.java index 5810005314b4..7ca777d7229b 100644 --- a/platform/core-impl/src/com/intellij/mock/MockProject.java +++ b/platform/core-impl/src/com/intellij/mock/MockProject.java @@ -16,6 +16,7 @@ package com.intellij.mock; import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -35,7 +36,7 @@ public class MockProject extends MockComponentManager implements Project { public MockProject(PicoContainer parent, @NotNull Disposable parentDisposable) { super(parent, parentDisposable); - Extensions.instantiateArea("IDEA_PROJECT", this, null); + Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); Disposer.register(parentDisposable, new Disposable() { @Override public void dispose() { diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 2c05de57807b..5ba93fd8b982 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -73,6 +73,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF private IElementType myElementType; protected IElementType myContentElementType; + private long myModificationStamp; protected PsiFile myOriginalFile = null; private final FileViewProvider myViewProvider; @@ -354,7 +355,9 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF myStub = null; } - public void clearCaches() {} + public void clearCaches() { + myModificationStamp ++; + } @Override public String getText() { @@ -386,7 +389,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF @Override public long getModificationStamp() { - return getViewProvider().getModificationStamp(); + return myModificationStamp; } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java index 53419feb35f6..f2673843b5b6 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java @@ -180,7 +180,7 @@ public class BlockSupportImpl extends BlockSupport { viewProvider.getLanguages(); FileType fileType = viewProvider.getVirtualFile().getFileType(); final LightVirtualFile lightFile = new LightVirtualFile(fileImpl.getName(), fileType, newFileText, viewProvider.getVirtualFile().getCharset(), - fileImpl.getModificationStamp()); + fileImpl.getViewProvider().getModificationStamp()); lightFile.setOriginalFile(viewProvider.getVirtualFile()); FileViewProvider copy = viewProvider.createCopy(lightFile); diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java index b80a4b6fc9be..fedbd19f2f48 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java @@ -20,9 +20,17 @@ package com.intellij.codeInsight.daemon; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface ChangeLocalityDetector { + /** + * @param changedElement + * @return the psi element (ancestor of the changedElement) which should be re-highlighted, or null if unsure. + * e.g. in Java we re-highlight enclosing code block only when element inside has changed. + * Note: do not traverse PSI tree upwards here, + * since this ChangeLocalityDetector will be called for the changed element and all its parents anyway. + */ @Nullable - PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement); + PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement); } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java b/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java index b9fba8d2bf57..cce3cd8c39e3 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java +++ b/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java @@ -33,7 +33,7 @@ public class LineRange { public LineRange(final int startLine, final int endLine) { this.startLine = startLine; this.endLine = endLine; - LOG.assertTrue(startLine > 0, "Negative start line"); + LOG.assertTrue(startLine >= 0, "Negative start line"); if (startLine > endLine) { LOG.error("start > end: start=" + startLine+"; end="+endLine); } diff --git a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index e7c4120a4109..07be796fde0a 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,9 +50,9 @@ public class EnvironmentVariablesComponent extends LabeledComponent myEnvs = new THashMap(); @NonNls private static final String ENVS = "envs"; - @NonNls private static final String ENV = "env"; - @NonNls private static final String NAME = "name"; - @NonNls private static final String VALUE = "value"; + @NonNls public static final String ENV = "env"; + @NonNls public static final String NAME = "name"; + @NonNls public static final String VALUE = "value"; @NonNls private static final String OPTION = "option"; @NonNls private static final String ENV_VARIABLES = "ENV_VARIABLES"; diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/SdkType.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/SdkType.java index bf87b86cf7c3..487d53c44b16 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/SdkType.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/SdkType.java @@ -65,6 +65,7 @@ public abstract class SdkType implements SdkTypeId { public abstract boolean isValidSdkHome(String path); + @Override @Nullable public String getVersionString(Sdk sdk) { return getVersionString(sdk.getHomePath()); @@ -92,8 +93,6 @@ public abstract class SdkType implements SdkTypeId { @Nullable public abstract AdditionalDataConfigurable createAdditionalDataConfigurable(SdkModel sdkModel, SdkModificator sdkModificator); - public abstract void saveAdditionalData(SdkAdditionalData additionalData, Element additional); - @Nullable public SdkAdditionalData loadAdditionalData(Element additional) { return null; diff --git a/platform/lang-api/src/com/intellij/ui/popup/util/ItemWrapper.java b/platform/lang-api/src/com/intellij/ui/popup/util/ItemWrapper.java index 6fffcc017028..331bcad134c2 100644 --- a/platform/lang-api/src/com/intellij/ui/popup/util/ItemWrapper.java +++ b/platform/lang-api/src/com/intellij/ui/popup/util/ItemWrapper.java @@ -31,7 +31,8 @@ import javax.swing.*; */ public interface ItemWrapper { void setupRenderer(ColoredListCellRenderer renderer, Project project, boolean selected); - void updateMnemonicLabel(JLabel label); + + void updateAccessoryView(JComponent label); void execute(Project project, JBPopup popup); diff --git a/platform/lang-api/src/com/intellij/ui/popup/util/SplitterItem.java b/platform/lang-api/src/com/intellij/ui/popup/util/SplitterItem.java index c4e1917bc439..2f9e5f96c660 100644 --- a/platform/lang-api/src/com/intellij/ui/popup/util/SplitterItem.java +++ b/platform/lang-api/src/com/intellij/ui/popup/util/SplitterItem.java @@ -46,7 +46,7 @@ public class SplitterItem implements ItemWrapper { } @Override - public void updateMnemonicLabel(JLabel label) { + public void updateAccessoryView(JComponent label) { //To change body of implemented methods use File | Settings | File Templates. } diff --git a/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java index d40d70cb1723..fcda8e15f6b2 100644 --- a/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java @@ -55,6 +55,7 @@ public abstract class TextEditorHighlightingPass implements HighlightingPass { this(project, document, true); } + @Override public final void collectInformation(ProgressIndicator progress) { if (!isValid()) return; //Document has changed. myDumb = DumbService.getInstance(myProject).isDumb(); @@ -88,6 +89,7 @@ public abstract class TextEditorHighlightingPass implements HighlightingPass { return true; } + @Override public final void applyInformationToEditor() { if (!isValid()) return; // Document has changed. if (DumbService.getInstance(myProject).isDumb() && !(this instanceof DumbAware)) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 3214d978bcca..2e1333b0919c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -785,7 +785,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { final Pair pair = reference.get(); if (pair != null && pair.first.isValid() && pair.first.getClass().equals(file.getClass())) { final PsiFile copy = pair.first; - if (copy.getModificationStamp() > file.getModificationStamp()) { + if (copy.getViewProvider().getModificationStamp() > file.getViewProvider().getModificationStamp()) { ((PsiModificationTrackerImpl) file.getManager().getModificationTracker()).incCounter(); } final Document document = pair.second; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/OffsetTranslator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/OffsetTranslator.java index bf21e70a6399..041e2a0f25d3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/OffsetTranslator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/OffsetTranslator.java @@ -59,10 +59,10 @@ public class OffsetTranslator implements Disposable { }); originalFile.getProject().getMessageBus().connect(this).subscribe(PsiModificationTracker.TOPIC, new PsiModificationTracker.Listener() { - long lastModCount = originalFile.getModificationStamp(); + long lastModCount = originalFile.getViewProvider().getModificationStamp(); @Override public void modificationCountChanged() { - if (isUpToDate() && lastModCount != originalFile.getModificationStamp()) { + if (isUpToDate() && lastModCount != originalFile.getViewProvider().getModificationStamp()) { myTranslation.addAll(sinceCommit); sinceCommit.clear(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index b9e0f7d040af..7dc5955bc4d9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -26,6 +26,7 @@ import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.ReferenceImporter; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.intention.impl.IntentionHintComponent; +import com.intellij.codeInspection.ex.InspectionProfileWrapper; import com.intellij.concurrency.Job; import com.intellij.ide.PowerSaveMode; import com.intellij.lang.annotation.HighlightSeverity; @@ -53,6 +54,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.packageDependencies.DependencyValidationManager; +import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; @@ -471,7 +473,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx if (myDisposed) return false; Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file); return document != null && - document.getModificationStamp() == file.getModificationStamp() && + document.getModificationStamp() == file.getViewProvider().getModificationStamp() && myFileStatusMap.allDirtyScopesAreNull(document); } @@ -479,7 +481,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx if (myDisposed) return false; Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file); return document != null && - document.getModificationStamp() == file.getModificationStamp() && + document.getModificationStamp() == file.getViewProvider().getModificationStamp() && myFileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL) == null; } @@ -749,10 +751,31 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myPassExecutorService.submitPasses(passes, progress, Job.DEFAULT_PRIORITY); } }; + + if (activeEditor == null) { runnable.run(); } else { + final InspectionProfileWrapper profile = InspectionProjectProfileManager.getInstance(myProject).getProfileWrapper(); + final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(activeEditor.getDocument()); + if (psiFile != null && profile != null && !profile.areToolsInstantiated()) { + // optimization: do expensive classloading outside readaction + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + try { + if (!psiFile.getManager().isDisposed() && !profile.areToolsInstantiated()) { + profile.preInstantiateTools(psiFile); + } + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).cancelAndRunWhenAllCommitted( "start daemon when all committed", runnable); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java new file mode 100644 index 000000000000..a822811aa845 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.impl; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.SuppressionUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import org.jetbrains.annotations.NotNull; + +public class DefaultChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + if (changedElement instanceof PsiWhiteSpace || + changedElement instanceof PsiComment + && !changedElement.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { + return changedElement; + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index f17a5504853a..ed110d1bd749 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -709,7 +709,8 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass return new ArrayList(result); } - List getInspectionTools(InspectionProfileWrapper profile) { + @NotNull + List getInspectionTools(@NotNull InspectionProfileWrapper profile) { final List tools = profile.getHighlightingLocalInspectionTools(myFile); for (Iterator iterator = tools.iterator(); iterator.hasNext(); ) { LocalInspectionToolWrapper tool = iterator.next(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index f148691cd732..956f39823ba5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; -import com.intellij.codeInspection.SuppressionUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -214,18 +213,9 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable return; } - // optimization - if (whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document)) { - if (child instanceof PsiWhiteSpace || - child instanceof PsiComment && !child.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { - myFileStatusMap.markFileScopeDirty(document, child.getTextRange(), fileLength); - return; - } - } - - PsiElement element = child; + PsiElement element = whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document) ? child : child.getParent(); while (true) { - if (element instanceof PsiFile || element instanceof PsiDirectory) { + if (element == null || element instanceof PsiFile || element instanceof PsiDirectory) { myFileStatusMap.markAllFilesDirty(); return; } @@ -242,10 +232,18 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable @Nullable private static PsiElement getChangeHighlightingScope(PsiElement element) { + DefaultChangeLocalityDetector defaultDetector = null; for (ChangeLocalityDetector detector : Extensions.getExtensions(EP_NAME)) { + if (detector instanceof DefaultChangeLocalityDetector) { + // run default detector last + assert defaultDetector == null : defaultDetector; + defaultDetector = (DefaultChangeLocalityDetector)detector; + continue; + } final PsiElement scope = detector.getChangeHighlightingDirtyScopeFor(element); if (scope != null) return scope; } - return null; + assert defaultDetector != null : "com.intellij.codeInsight.daemon.impl.DefaultChangeLocalityDetector is unregistered"; + return defaultDetector.getChangeHighlightingDirtyScopeFor(element); } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java index c2052337d83b..35a5ee5873bb 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java @@ -22,8 +22,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.util.Function; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -66,9 +68,9 @@ public class InspectionProfileWrapper { return enabled; } - // check whether some inspection got registered twice by accident. Bit only once. + // check whether some inspection got registered twice by accident. 've bit once. private static boolean alreadyChecked; - private static void checkInspectionsDuplicates(InspectionTool[] tools) { + private static void checkInspectionsDuplicates(@NotNull InspectionTool[] tools) { if (alreadyChecked) return; alreadyChecked = true; Set uniqTools = new THashSet(tools.length); @@ -79,6 +81,22 @@ public class InspectionProfileWrapper { } } + private volatile boolean toolsInstantiated; + public void preInstantiateTools(PsiFile psiFile) { + if (toolsInstantiated) return; + toolsInstantiated = true; + InspectionTool[] tools = getInspectionTools(psiFile); + for (InspectionTool tool : tools) { + if (tool instanceof InspectionToolWrapper) { + ((InspectionToolWrapper)tool).getTool(); + } + } + } + + public boolean areToolsInstantiated() { + return toolsInstantiated; + } + public String getName() { return myProfile.getName(); } @@ -105,13 +123,10 @@ public class InspectionProfileWrapper { } public void cleanup(final Project project){ - myProfile.cleanup(project); } public InspectionProfile getInspectionProfile() { return myProfile; } - - } diff --git a/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java b/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java new file mode 100644 index 000000000000..101ee0304c6f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/configuration/RunConfigurationPathMacroFilter.java @@ -0,0 +1,46 @@ +/* + * 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.execution.configuration; + +import com.intellij.openapi.application.PathMacroFilter; +import org.jdom.Attribute; +import org.jdom.Element; + +/** + * @author yole + */ +public class RunConfigurationPathMacroFilter extends PathMacroFilter { + @Override + public boolean skipPathMacros(Attribute attribute) { + final Element parent = attribute.getParent(); + final String attrName = attribute.getName(); + if (parent.getName().equals(EnvironmentVariablesComponent.ENV) && + (attrName.equals(EnvironmentVariablesComponent.NAME) || attrName.equals(EnvironmentVariablesComponent.VALUE))) { + return true; + } + return false; + } + + @Override + public boolean recursePathMacros(Attribute attribute) { + final Element parent = attribute.getParent(); + if (parent != null && "option".equals(parent.getName())) { + final Element grandParent = parent.getParentElement(); + return grandParent != null && "configuration".equals(grandParent.getName()); + } + return false; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java b/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java index 6739f71e1bf2..bfe3145039dc 100644 --- a/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java +++ b/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java @@ -89,7 +89,8 @@ public class BookmarkItem implements ItemWrapper { } } - public void updateMnemonicLabel(JLabel label) { + public void updateAccessoryView(JComponent component) { + JLabel label = (JLabel)component; final char mnemonic = myBookmark.getMnemonic(); if (mnemonic != 0) { label.setText(Character.toString(mnemonic) + '.'); diff --git a/platform/lang-impl/src/com/intellij/ide/bookmarks/actions/BookmarksAction.java b/platform/lang-impl/src/com/intellij/ide/bookmarks/actions/BookmarksAction.java index c69805161528..99d3c7be6b7e 100644 --- a/platform/lang-impl/src/com/intellij/ide/bookmarks/actions/BookmarksAction.java +++ b/platform/lang-impl/src/com/intellij/ide/bookmarks/actions/BookmarksAction.java @@ -34,6 +34,7 @@ import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.components.JBList; import com.intellij.ui.popup.util.MasterDetailPopupBuilder; import com.intellij.ui.speedSearch.FilteringListModel; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.KeyEvent; @@ -99,6 +100,19 @@ public class BookmarksAction extends AnAction implements DumbAware, MasterDetail } } + @Nullable + public JComponent createAccessoryView(Project project) { + if (!BookmarkManager.getInstance(project).hasBookmarksWithMnemonics()) { + return null; + } + final JLabel mnemonicLabel = new JLabel(); + mnemonicLabel.setFont(Bookmark.MNEMONIC_FONT); + + mnemonicLabel.setPreferredSize(new JLabel("W.").getPreferredSize()); + mnemonicLabel.setOpaque(false); + return mnemonicLabel; + } + private static DefaultListModel buildModel(Project project) { final DefaultListModel model = new DefaultListModel(); @@ -109,10 +123,6 @@ public class BookmarksAction extends AnAction implements DumbAware, MasterDetail return model; } - public boolean hasItemsWithMnemonic(Project project) { - return BookmarkManager.getInstance(project).hasBookmarksWithMnemonics(); - } - protected static class BookmarkInContextInfo { private final DataContext myDataContext; private final Project myProject; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 7ad24cee508c..fcf4e6d58a65 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -59,7 +59,12 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C private Pattern myCompiledPattern; private final PatternMatcher myMatcher = new Perl5Matcher(); - private Map myActionsMap = new HashMap(); + private Map myActionsMap = new TreeMap(new Comparator() { + @Override + public int compare(AnAction o1, AnAction o2) { + return Comparing.compare(o1.getTemplatePresentation().getText(), o2.getTemplatePresentation().getText()); + } + }); private final SearchableOptionsRegistrar myIndex; @@ -289,6 +294,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C } } final Object[] descriptions = optionDescriptions.toArray(); + Arrays.sort(descriptions); objects = ArrayUtil.mergeArrays(objects, descriptions); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java index a6932b6b2e4d..614c466319f1 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ class ModuleStateStorageManager extends StateStorageManagerImpl { myModule = module; } - protected XmlElementStorage.StorageData createStorageData(String storageSpec) { + protected StorageData createStorageData(String storageSpec) { return new ModuleStoreImpl.ModuleFileData(ROOT_TAG_NAME, myModule); } diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java index c7304c1774ea..0075de8abdb5 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,7 +112,7 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM myModule = storageData.myModule; } - protected void load(@NotNull final Element rootElement) throws IOException { + public void load(@NotNull final Element rootElement) throws IOException { super.load(rootElement); final List attributes = rootElement.getAttributes(); @@ -145,7 +145,7 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM return root; } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new ModuleFileData(this); } @@ -154,7 +154,7 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM } @Nullable - public Set getDifference(final XmlElementStorage.StorageData storageData, PathMacroSubstitutor substitutor) { + public Set getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) { final ModuleFileData data = (ModuleFileData)storageData; if (!myOptions.equals(data.myOptions)) return null; return super.getDifference(storageData, substitutor); diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java index 9931d53c3dc3..dc377069df0a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java @@ -20,6 +20,7 @@ import com.intellij.ide.highlighter.ModuleFileType; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.application.impl.ApplicationInfoImpl; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.components.impl.ModulePathMacroManager; import com.intellij.openapi.components.impl.stores.IComponentStore; @@ -85,7 +86,7 @@ public class ModuleImpl extends ComponentManagerImpl implements ModuleEx { } protected void bootstrapPicoContainer() { - Extensions.instantiateArea(PluginManager.AREA_IDEA_MODULE, this, (AreaInstance)getParentComponentManager()); + Extensions.instantiateArea(ExtensionAreas.IDEA_MODULE, this, (AreaInstance)getParentComponentManager()); super.bootstrapPicoContainer(); getPicoContainer().registerComponentImplementation(IComponentStore.class, ModuleStoreImpl.class); getPicoContainer().registerComponentImplementation(ModulePathMacroManager.class); diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java index b9e76f1ee391..4e46683a898a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.*; @@ -164,29 +163,6 @@ public class ProjectJdkTableImpl extends ProjectJdkTable implements PersistentSt return result; } - @Override - public Sdk findMostRecentSdkOfType(final SdkTypeId type) { - return findMostRecentSdk(new Condition() { - public boolean value(Sdk sdk) { - return sdk.getSdkType() == type; - } - }); - } - - @Override - public Sdk findMostRecentSdk(Condition condition) { - Sdk found = null; - for (Sdk each : getAllJdks()) { - if (!condition.value(each)) continue; - if (found == null) { - found = each; - continue; - } - if (Comparing.compare(each.getVersionString(), found.getVersionString()) > 0) found = each; - } - return found; - } - public void addJdk(Sdk jdk) { ApplicationManager.getApplication().assertWriteAccessAllowed(); mySdks.add(jdk); @@ -223,8 +199,23 @@ public class ProjectJdkTableImpl extends ProjectJdkTable implements PersistentSt return UnknownSdkType.getInstance(null); } + @Override + public SdkTypeId getSdkTypeByName(String sdkTypeName) { + return findSdkTypeByName(sdkTypeName); + } + + public static SdkTypeId findSdkTypeByName(String sdkTypeName) { + final SdkType[] allSdkTypes = SdkType.getAllTypes(); + for (final SdkType type : allSdkTypes) { + if (type.getName().equals(sdkTypeName)) { + return type; + } + } + return UnknownSdkType.getInstance(sdkTypeName); + } + public Sdk createSdk(final String name, final SdkTypeId sdkType) { - return new ProjectJdkImpl(name, (SdkType) sdkType); + return new ProjectJdkImpl(name, sdkType); } public void loadState(Element element) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexComponent.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexComponent.java index bbb30af153ea..bee9deaa4f8f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexComponent.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexComponent.java @@ -117,7 +117,7 @@ public class DirectoryIndexComponent extends DirectoryIndexImpl { VirtualFile f = file.findFileByRelativePath(rel); if (f != null) { if (state == originalState) state = state.copy(); - state.fillMapWithModuleContent(f, eachModule, f); + state.fillMapWithModuleContent(f, eachModule, f, null); } } } @@ -133,29 +133,29 @@ public class DirectoryIndexComponent extends DirectoryIndexImpl { } if (state == originalState) state = state.copy(); - state.fillMapWithModuleContent(file, module, parentInfo.contentRoot); + state.fillMapWithModuleContent(file, module, parentInfo.contentRoot, null); String parentPackage = state.myDirToPackageName.get(parent); if (module != null) { if (parentInfo.isInModuleSource) { String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithModuleSource(file, module, newDirPackageName, parentInfo.sourceRoot, parentInfo.isTestSource); + state.fillMapWithModuleSource(file, module, newDirPackageName, parentInfo.sourceRoot, parentInfo.isTestSource, null); } } if (parentInfo.libraryClassRoot != null) { String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithLibraryClasses(file, newDirPackageName, parentInfo.libraryClassRoot); + state.fillMapWithLibraryClasses(file, newDirPackageName, parentInfo.libraryClassRoot, null); } if (parentInfo.isInLibrarySource) { String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithLibrarySources(file, newDirPackageName, parentInfo.sourceRoot); + state.fillMapWithLibrarySources(file, newDirPackageName, parentInfo.sourceRoot, null); } if (!parentInfo.getOrderEntries().isEmpty()) { - state.fillMapWithOrderEntries(file, parentInfo.getOrderEntries(), null, null, null, parentInfo); + state.fillMapWithOrderEntries(file, parentInfo.getOrderEntries(), null, null, null, parentInfo, null); } return state; } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java new file mode 100644 index 000000000000..b1dfa25ac1ef --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java @@ -0,0 +1,45 @@ +/* + * 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.openapi.roots.impl.libraries; + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.project.ProjectBundle; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author yole + */ +@State( + name = "libraryTable", + roamingType = RoamingType.DISABLED, + storages = { + @Storage( file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml") + } +) +public class ExportableApplicationLibraryTable extends ApplicationLibraryTable implements ExportableComponent { + @NotNull + public File[] getExportFiles() { + return new File[]{PathManager.getOptionsFile(getExternalFileName())}; + } + + @NotNull + public String getPresentableName() { + return ProjectBundle.message("library.global.settings"); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java index 6f84cd1c8266..2ce83f870330 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ContentEntryEditor.java @@ -72,14 +72,17 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb myMainPanel = new JPanel(new BorderLayout()); myMainPanel.setOpaque(false); myMainPanel.addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { myEventDispatcher.getMulticaster().editingStarted(ContentEntryEditor.this); } + @Override public void mouseEntered(MouseEvent e) { if (!myIsSelected) { highlight(true); } } + @Override public void mouseExited(MouseEvent e) { if (!myIsSelected) { highlight(false); @@ -106,6 +109,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb protected abstract ModifiableRootModel getModel(); + @Override public void deleteContentEntry() { final String path = FileUtil.toSystemDependentName(VfsUtil.urlToPath(myContentEntryUrl)); final int answer = Messages.showYesNoDialog(ProjectBundle.message("module.paths.remove.content.prompt", path), @@ -120,6 +124,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } } + @Override public void deleteContentFolder(ContentEntry contentEntry, ContentFolder folder) { if (folder instanceof SourceFolder) { removeSourceFolder((SourceFolder)folder); @@ -132,6 +137,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } + @Override public void navigateFolder(ContentEntry contentEntry, ContentFolder contentFolder) { final VirtualFile file = contentFolder.getFile(); if (file != null) { // file can be deleted externally @@ -139,6 +145,7 @@ public abstract class ContentEntryEditor implements ContentRootPanel.ActionCallb } } + @Override public void setPackagePrefix(SourceFolder folder, String prefix) { folder.setPackagePrefix(prefix); update(); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java index 89b421d2249c..9cf95dcd0367 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java @@ -96,7 +96,7 @@ public class PsiToDocumentSynchronizer extends PsiTreeChangeAdapter { final boolean insideTransaction = myTransactionsMap.containsKey(document); if (!insideTransaction) { - document.setModificationStamp(psiFile.getModificationStamp()); + document.setModificationStamp(psiFile.getViewProvider().getModificationStamp()); if (LOG.isDebugEnabled()) { PsiDocumentManagerImpl.checkConsistency(psiFile, document); } diff --git a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java index 7d861bdbf8a2..269c38ca500b 100644 --- a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java @@ -54,7 +54,7 @@ public class DetailViewImpl extends JPanel implements DetailView { public DetailViewImpl(Project project) { super(new BorderLayout()); myProject = project; - setPreferredSize(new Dimension(600, 400)); + setPreferredSize(new Dimension(700, 400)); myNothingToShow.setHorizontalAlignment(JLabel.CENTER); myNothingToShowInEditor.setHorizontalAlignment(JLabel.CENTER); } @@ -164,17 +164,12 @@ public class DetailViewImpl extends JPanel implements DetailView { if (panel != null) { if (myDetailScrollPanel == null) { myDetailPanelWrapper = new JPanel(new GridLayout(1, 1)); - myDetailPanelWrapper.setBorder(BorderFactory.createEmptyBorder(5, 30, 5, 10)); + myDetailPanelWrapper.setBorder(BorderFactory.createEmptyBorder(5, 30, 5, 30)); myDetailPanelWrapper.add(panel); myDetailScrollPanel = - new JBScrollPane(myDetailPanelWrapper, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) { - @Override - public Dimension getPreferredSize() { - final Dimension size = panel.getPreferredSize(); - return new Dimension(size.width, size.height + 10); - } - }; + new JBScrollPane(myDetailPanelWrapper, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + myDetailScrollPanel.setPreferredSize(myDetailPanelWrapper.getPreferredSize()); myDetailScrollPanel.setBorder(null); add(myDetailScrollPanel, BorderLayout.SOUTH); } else { diff --git a/platform/lang-impl/src/com/intellij/ui/popup/util/MasterDetailPopupBuilder.java b/platform/lang-impl/src/com/intellij/ui/popup/util/MasterDetailPopupBuilder.java index b89274533ef5..4df48c798aa1 100644 --- a/platform/lang-impl/src/com/intellij/ui/popup/util/MasterDetailPopupBuilder.java +++ b/platform/lang-impl/src/com/intellij/ui/popup/util/MasterDetailPopupBuilder.java @@ -15,7 +15,6 @@ */ package com.intellij.ui.popup.util; -import com.intellij.ide.bookmarks.Bookmark; import com.intellij.ide.bookmarks.BookmarkItem; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionManager; @@ -33,6 +32,7 @@ import com.intellij.ui.speedSearch.FilteringListModel; import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; @@ -80,7 +80,7 @@ public class MasterDetailPopupBuilder { final Alarm updateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); final DetailViewImpl detailView = new DetailViewImpl(myProject); - myList.setCellRenderer(new ItemRenderer(myProject)); + myList.setCellRenderer(new ItemRenderer(myDelegate, myProject)); final ListSelectionModel selectionModel = myList.getSelectionModel(); selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -301,26 +301,24 @@ public class MasterDetailPopupBuilder { void handleMnemonic(KeyEvent e, Project project, JBPopup popup); - boolean hasItemsWithMnemonic(Project project); + @Nullable + JComponent createAccessoryView(Project project); } - public class ItemRenderer extends JPanel implements ListCellRenderer { + public static class ItemRenderer extends JPanel implements ListCellRenderer { private final Project myProject; private final ColoredListCellRenderer myRenderer; + private Delegate myDelegate; - private ItemRenderer(Project project) { + private ItemRenderer(Delegate delegate, Project project) { super(new BorderLayout()); myProject = project; setBackground(UIUtil.getListBackground()); - final JLabel mnemonicLabel = new JLabel(); - mnemonicLabel.setFont(Bookmark.MNEMONIC_FONT); + this.myDelegate = delegate; + final JComponent accessory = myDelegate.createAccessoryView(project); - mnemonicLabel.setPreferredSize(new JLabel("W.").getPreferredSize()); - mnemonicLabel.setOpaque(false); - - final boolean hasMnemonics = myDelegate.hasItemsWithMnemonic(project); - if (hasMnemonics) { - add(mnemonicLabel, BorderLayout.WEST); + if (accessory != null) { + add(accessory, BorderLayout.WEST); } myRenderer = new ColoredListCellRenderer() { @@ -329,8 +327,8 @@ public class MasterDetailPopupBuilder { if (value instanceof ItemWrapper) { final ItemWrapper wrapper = (ItemWrapper)value; wrapper.setupRenderer(this, myProject, selected); - if (hasMnemonics) { - wrapper.updateMnemonicLabel(mnemonicLabel); + if (accessory != null) { + wrapper.updateAccessoryView(accessory); } } } @@ -338,7 +336,6 @@ public class MasterDetailPopupBuilder { add(myRenderer, BorderLayout.CENTER); } - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (value instanceof SplitterItem) { String label = ((SplitterItem)value).getText(); @@ -349,8 +346,8 @@ public class MasterDetailPopupBuilder { } myRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); myRenderer.revalidate(); + return this; } } - } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index e2ae3217f0d8..b804aa97bef2 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -1384,7 +1384,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @Override public String getText() { - if (myFile.getModificationStamp() != myDocument.getModificationStamp()) { + if (myFile.getViewProvider().getModificationStamp() != myDocument.getModificationStamp()) { final ASTNode node = myFile.getNode(); assert node != null; return node.getText(); @@ -1394,7 +1394,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @Override public long getModificationStamp() { - return myFile.getModificationStamp(); + return myFile.getViewProvider().getModificationStamp(); } } @@ -1418,7 +1418,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); final DocumentContent content; - if (dominantContentFile != null && dominantContentFile.getModificationStamp() != document.getModificationStamp()) { + if (dominantContentFile != null && dominantContentFile.getViewProvider().getModificationStamp() != document.getModificationStamp()) { content = new PsiContent(document, dominantContentFile); } else { diff --git a/platform/platform-api/platform-api.iml b/platform/platform-api/platform-api.iml index c98c76e7e541..4b0040d1c9c4 100644 --- a/platform/platform-api/platform-api.iml +++ b/platform/platform-api/platform-api.iml @@ -28,7 +28,7 @@ - + diff --git a/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java b/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java index 1d7ddf517976..3345439bed79 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java @@ -202,9 +202,16 @@ public class PopupChooserBuilder { } + final JList finalList = list; (list != null ? list : myChooserComponent).addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { + + final Point onScreen = e.getLocationOnScreen(); + SwingUtilities.convertPointFromScreen(onScreen, finalList); + + final int index = finalList.locationToIndex(onScreen); + if (finalList.getSelectedIndex() != index) return; if (UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED) && !UIUtil.isSelectionButtonDown(e) && !e.isConsumed()) { if (myCloseOnEnter) { closePopup(true, e, true); diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/JarFileSystem.java b/platform/platform-api/src/com/intellij/openapi/vfs/JarFileSystem.java index 6251932479e6..4eb914886771 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/JarFileSystem.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/JarFileSystem.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.zip.ZipFile; -public abstract class JarFileSystem extends NewVirtualFileSystem { +public abstract class JarFileSystem extends NewVirtualFileSystem implements JarCopyingFileSystem { @NonNls public static final String PROTOCOL = StandardFileSystems.JAR_PROTOCOL; @NonNls public static final String PROTOCOL_PREFIX = "jar://"; @NonNls public static final String JAR_SEPARATOR = StandardFileSystems.JAR_SEPARATOR; @@ -36,8 +36,6 @@ public abstract class JarFileSystem extends NewVirtualFileSystem { public abstract VirtualFile getVirtualFileForJar(@Nullable VirtualFile entryVFile); public abstract ZipFile getJarFile(VirtualFile entryVFile) throws IOException; - public abstract void setNoCopyJarForPath(String pathInJar); - @SuppressWarnings("MethodMayBeStatic") @Nullable public VirtualFile getJarRootForLocalFile(@NotNull VirtualFile virtualFile) { diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java index d097586c6be9..38675fe45e03 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java @@ -403,11 +403,6 @@ public class VfsUtil extends VfsUtilCore { return protocol + "://" + path; } - @NotNull - public static String pathToUrl(@NonNls @NotNull String path) { - return VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, path); - } - @NotNull public static IFile virtualToIFile(@NotNull VirtualFile file) { return FileSystem.FILE_SYSTEM.createFile(PathUtil.toPresentableUrl(file.getUrl())); diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java b/platform/platform-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java index d140fe3de328..7f68e0845bb6 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,14 @@ package com.intellij.openapi.vfs.ex.http; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem; +import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public abstract class HttpFileSystem extends DeprecatedVirtualFileSystem implements ApplicationComponent { - @NonNls public static final String PROTOCOL = "http"; + @NonNls public static final String PROTOCOL = StandardFileSystems.HTTP_PROTOCOL; public static HttpFileSystem getInstance() { return (HttpFileSystem)VirtualFileManager.getInstance().getFileSystem(PROTOCOL); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java index 9f2c57e529c6..b93eb4736d10 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import com.intellij.notification.Notifications; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.LogProvider; @@ -74,8 +75,6 @@ import java.util.zip.ZipInputStream; @SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace"}) // No logger is loaded at this time so we have to use these. public class PluginManager { - @NonNls public static final String AREA_IDEA_PROJECT = "IDEA_PROJECT"; - @NonNls public static final String AREA_IDEA_MODULE = "IDEA_MODULE"; @NonNls private static final String PROPERTY_PLUGIN_PATH = "plugin.path"; private static final Object PLUGIN_CLASSES_LOCK = new Object(); private static String myPluginError = null; @@ -318,8 +317,8 @@ public class PluginManager { private static void configureExtensions() { Extensions.setLogProvider(new IdeaLogProvider()); - Extensions.registerAreaClass(AREA_IDEA_PROJECT, null); - Extensions.registerAreaClass(AREA_IDEA_MODULE, AREA_IDEA_PROJECT); + Extensions.registerAreaClass(ExtensionAreas.IDEA_PROJECT, null); + Extensions.registerAreaClass(ExtensionAreas.IDEA_MODULE, ExtensionAreas.IDEA_PROJECT); } private static boolean shouldLoadPlugins() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index 73114f7aa0cb..82268d3ef782 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -197,8 +197,8 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { myStorage.put(new String(option), configs); } - configs.add(new OptionDescription(null, myIdentifierTable.intern(id), hit != null ? myIdentifierTable.intern(hit) : null, - path != null ? myIdentifierTable.intern(path) : null)); + configs.add(new OptionDescription(null, myIdentifierTable.intern(id).trim(), hit != null ? myIdentifierTable.intern(hit).trim() : null, + path != null ? myIdentifierTable.intern(path).trim() : null)); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java index af32c65f518c..a2ae2f43aae1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java @@ -48,7 +48,7 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto public ApplicationStoreImpl(final ApplicationImpl application, PathMacroManager pathMacroManager) { myApplication = application; myStateStorageManager = new StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), ROOT_ELEMENT_NAME, application, application.getPicoContainer()) { - protected XmlElementStorage.StorageData createStorageData(String storageSpec) { + protected StorageData createStorageData(String storageSpec) { return new FileBasedStorage.FileStorageData(ROOT_ELEMENT_NAME); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java index c0fe7ca8a302..7c6254b34006 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,7 +62,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { } @Override - protected void load(@NotNull final Element rootElement) throws IOException { + public void load(@NotNull final Element rootElement) throws IOException { super.load(rootElement); final String v = rootElement.getAttributeValue(VERSION_OPTION); @@ -83,7 +83,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { } @Override - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new BaseStorageData(this); } @@ -96,7 +96,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl { @Override @Nullable - public Set getDifference(final XmlElementStorage.StorageData storageData, PathMacroSubstitutor substitutor) { + public Set getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) { final BaseStorageData data = (BaseStorageData)storageData; if (myVersion != data.myVersion) return null; return super.getDifference(storageData, substitutor); 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 5ab67f2fc460..0fc2147f8a1a 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 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; @@ -30,14 +29,9 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileAdapter; import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.openapi.vfs.tracker.VirtualFileTracker; -import com.intellij.util.PairConsumer; import com.intellij.util.io.fs.IFile; import com.intellij.util.messages.MessageBus; -import gnu.trove.THashMap; -import org.jdom.Document; import org.jdom.Element; -import org.jdom.JDOMException; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.picocontainer.PicoContainer; @@ -59,9 +53,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { private final StateSplitter mySplitter; private Object mySession; - private MyStorageData myStorageData = null; - @NonNls private static final String COMPONENT = "component"; - @NonNls private static final String NAME = "name"; + private DirectoryStorageData myStorageData = null; private static final IFile[] EMPTY_FILES = new IFile[0]; @@ -116,66 +108,15 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { if (!myStorageData.containsComponent(componentName)) { - return DefaultStateSerializer.deserializeState(new Element(COMPONENT), stateClass, mergeInto); + return DefaultStateSerializer.deserializeState(new Element(StorageData.COMPONENT), stateClass, mergeInto); } - final List subElements = new ArrayList(); - myStorageData.processComponent(componentName, new PairConsumer() { - public void consume(final IFile iFile, final Element element) { - final List children = element.getChildren(); - assert children.size() == 1 : JDOMUtil.writeElement(element, File.separator); - final Element subElement = (Element)children.get(0); - subElement.detach(); - subElements.add(subElement); - } - }); - - final Element state = new Element(COMPONENT); - mySplitter.mergeStatesInto(state, subElements.toArray(new Element[subElements.size()])); - myStorageData.removeComponent(componentName); - - return DefaultStateSerializer.deserializeState(state, stateClass, mergeInto); + return myStorageData.getMergedState(componentName, stateClass, mySplitter, mergeInto); } - private MyStorageData loadState() throws StateStorageException { - MyStorageData storageData = new MyStorageData(); - if (!myDir.exists()) { - return storageData; - } - - final IFile[] files = myDir.listFiles(); - - for (IFile file : files) { - if (!StringUtil.endsWithIgnoreCase(file.getName(), ".xml")) { - //do not load system files like .DS_Store on Mac - continue; - } - - try { - final Document document = JDOMUtil.loadDocument(file); - final Element element = document.getRootElement(); - assert element.getName().equals(COMPONENT); - - String componentName = element.getAttributeValue(NAME); - assert componentName != null; - - if (myPathMacroSubstitutor != null) { - myPathMacroSubstitutor.expandPaths(element); - - final Set unknownMacros = StorageUtil.getMacroNames(element); - myPathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros); - } - - storageData.put(componentName, file, element, true); - } - catch (IOException e) { - LOG.info("Unable to load state", e); - } - catch (JDOMException e) { - LOG.info("Unable to load state", e); - } - } - + private DirectoryStorageData loadState() throws StateStorageException { + DirectoryStorageData storageData = new DirectoryStorageData(); + storageData.loadFrom(myDir, myPathMacroSubstitutor); return storageData; } @@ -228,10 +169,10 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { } private class MySaveSession implements SaveSession { - private final MyStorageData myStorageData; + private final DirectoryStorageData myStorageData; private final TrackingPathMacroSubstitutor myPathMacroSubstitutor; - private MySaveSession(final MyStorageData storageData, final TrackingPathMacroSubstitutor pathMacroSubstitutor) { + private MySaveSession(final DirectoryStorageData storageData, final TrackingPathMacroSubstitutor pathMacroSubstitutor) { myStorageData = storageData; myPathMacroSubstitutor = pathMacroSubstitutor; } @@ -248,7 +189,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { } } - myStorageData.process(new StorageDataProcessor() { + myStorageData.process(new DirectoryStorageData.StorageDataProcessor() { public void process(final String componentName, final IFile file, final Element element) { currentNames.remove(file.getName()); @@ -318,7 +259,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { if (myStorageData.getComponentNames().size() == 0) { // no state yet, so try to initialize it now - final MyStorageData storageData = loadState(); + final DirectoryStorageData storageData = loadState(); return new HashSet(storageData.getComponentNames()); } @@ -339,7 +280,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { if (!myFileTypeManager.isFileIgnored(child.getName())) currentChildNames.add(child.getName()); } - myStorageData.process(new StorageDataProcessor() { + myStorageData.process(new DirectoryStorageData.StorageDataProcessor() { public void process(final String componentName, final IFile file, final Element element) { if (currentChildNames.contains(file.getName())) { currentChildNames.remove(file.getName()); @@ -369,97 +310,10 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { } } - private interface StorageDataProcessor { - void process(String componentName, IFile file, Element element); - } - - private static class MyStorageData { - private Map> myStates = new HashMap>(); - private long myLastTimestamp = 0; - private MyStorageData myOriginalData; - - public Set getComponentNames() { - return myStates.keySet(); - } - - public void put(final String componentName, final IFile file, final Element element, final boolean updateTimestamp) { - LOG.assertTrue(componentName != null, String.format("Component name should not be null for file: %s", file == null ? "NULL!" : file.getPath())); - - Map stateMap = myStates.get(componentName); - if (stateMap == null) { - stateMap = new HashMap(); - myStates.put(componentName, stateMap); - } - - stateMap.put(file, element); - if (updateTimestamp) updateLastTimestamp(file); - } - - public void updateLastTimestamp(final IFile file) { - myLastTimestamp = Math.max(myLastTimestamp, file.getTimeStamp()); - if (myOriginalData != null) myOriginalData.myLastTimestamp = myLastTimestamp; - } - - public long getLastTimeStamp() { - return myLastTimestamp; - } - - public Map getAllStorageFiles() { - final Map allStorageFiles = new THashMap(); - process(new StorageDataProcessor() { - public void process(final String componentName, final IFile file, final Element element) { - allStorageFiles.put(file, file.getTimeStamp()); - } - }); - - return allStorageFiles; - } - - public void processComponent(@NotNull final String componentName, @NotNull final PairConsumer consumer) { - final Map map = myStates.get(componentName); - if (map != null) { - for (IFile file : map.keySet()) { - consumer.consume(file, map.get(file)); - } - } - } - - public void process(@NotNull final StorageDataProcessor processor) { - for (final String componentName : myStates.keySet()) { - processComponent(componentName, new PairConsumer() { - public void consume(final IFile iFile, final Element element) { - processor.process(componentName, iFile, element); - } - }); - } - } - - protected MyStorageData clone() { - final MyStorageData result = new MyStorageData(); - result.myStates = new HashMap>(myStates); - result.myLastTimestamp = myLastTimestamp; - result.myOriginalData = this; - return result; - } - - public void clear() { - myStates.clear(); - myOriginalData = null; - } - - public boolean containsComponent(final String componentName) { - return myStates.get(componentName) != null; - } - - public void removeComponent(final String componentName) { - myStates.remove(componentName); - } - } - private class MyExternalizationSession implements ExternalizationSession { - private final MyStorageData myStorageData; + private final DirectoryStorageData myStorageData; - private MyExternalizationSession(final TrackingPathMacroSubstitutor pathMacroSubstitutor, final MyStorageData storageData) { + private MyExternalizationSession(final TrackingPathMacroSubstitutor pathMacroSubstitutor, final DirectoryStorageData storageData) { myStorageData = storageData; } @@ -478,8 +332,8 @@ public class DirectoryBasedStorage implements StateStorage, Disposable { Element e = pair.first; String name = pair.second; - Element statePart = new Element(COMPONENT); - statePart.setAttribute(NAME, componentName); + Element statePart = new Element(StorageData.COMPONENT); + statePart.setAttribute(StorageData.NAME, componentName); e.detach(); statePart.addContent(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java index c63627836cf2..06daccdabd6d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java @@ -32,17 +32,17 @@ class ProjectStateStorageManager extends StateStorageManagerImpl { myProject = project; } - protected XmlElementStorage.StorageData createStorageData(String storageSpec) { + protected StorageData createStorageData(String storageSpec) { if (storageSpec.equals(StoragePathMacros.PROJECT_FILE)) return createIprStorageData(); if (storageSpec.equals(StoragePathMacros.WORKSPACE_FILE)) return createWsStorageData(); return new ProjectStoreImpl.ProjectStorageData(ROOT_TAG_NAME, myProject); } - public XmlElementStorage.StorageData createWsStorageData() { + public StorageData createWsStorageData() { return new ProjectStoreImpl.WsStorageData(ROOT_TAG_NAME, myProject); } - public XmlElementStorage.StorageData createIprStorageData() { + public StorageData createIprStorageData() { return new ProjectStoreImpl.IprStorageData(ROOT_TAG_NAME, myProject); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java index 816f17681b13..7c25f4a98211 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java @@ -418,7 +418,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject myProject = storageData.myProject; } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new ProjectStorageData(this); } } @@ -432,7 +432,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject super(storageData); } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new WsStorageData(this); } } @@ -446,7 +446,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject super(storageData); } - protected void load(@NotNull final Element root) throws IOException { + public void load(@NotNull final Element root) throws IOException { final String v = root.getAttributeValue(VERSION_OPTION); //noinspection AssignmentToStaticFieldFromInstanceMethod originalVersion = v != null ? Integer.parseInt(v) : 0; @@ -461,7 +461,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject protected void convert(final Element root, final int originalVersion) { } - public XmlElementStorage.StorageData clone() { + public StorageData clone() { return new IprStorageData(this); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index a8f94b8a3fb5..f94de9961761 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -376,7 +376,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di } - protected abstract XmlElementStorage.StorageData createStorageData(String storageSpec); + protected abstract StorageData createStorageData(String storageSpec); private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)"); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java index 6db45036ca44..1d5f917b1990 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.intellij.openapi.components.impl.stores; -import com.intellij.application.options.PathMacrosCollector; import com.intellij.notification.*; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; @@ -39,18 +38,23 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.NotNullFunction; import com.intellij.util.SystemProperties; import com.intellij.util.UniqueFileNamesProvider; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.fs.FileSystem; import com.intellij.util.io.fs.IFile; -import org.jdom.*; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.Parent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; @@ -225,45 +229,6 @@ public class StorageUtil { return JDOMUtil.writeElement(element, lineSeparator); } - @NotNull - public static Set getMacroNames(@NotNull final Element e) { - return PathMacrosCollector.getMacroNames(e, new NotNullFunction() { - @NotNull - public Boolean fun(Object o) { - if (o instanceof Attribute) { - final Attribute attribute = (Attribute)o; - final Element parent = attribute.getParent(); - final String parentName = parent.getName(); - if (("value".equals(attribute.getName()) || "name".equals(attribute.getName())) && "env".equals(parentName)) { - return false; // do not proceed environment variables from run configurations - } - - if ("MESSAGE".equals(parentName) && "value".equals(attribute.getName())) return false; - if ("option".equals(parentName) && "LAST_COMMIT_MESSAGE".equals(parent.getAttributeValue("name"))) return false; - - // do not proceed macros in searchConfigurations (structural search) - if ("replaceConfiguration".equals(parentName) || "searchConfiguration".equals(parentName)) return false; - } - - return true; - } - }, new NotNullFunction() { - @NotNull - public Boolean fun(Object o) { - if (o instanceof Attribute) { - // process run configuration's options recursively - final Element parent = ((Attribute)o).getParent(); - if (parent != null && "option".equals(parent.getName())) { - final Element grandParent = parent.getParentElement(); - return grandParent != null && "configuration".equals(grandParent.getName()); - } - } - - return false; - } - }); - } - @Nullable public static Document loadDocument(final byte[] bytes) { try { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index b45195bbbad0..700c9e97f943 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -18,19 +18,15 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.ExtensionPoint; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.StreamProvider; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ArrayUtil; import com.intellij.util.containers.StringInterner; import com.intellij.util.io.fs.IFile; import gnu.trove.THashMap; -import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -41,14 +37,9 @@ import java.io.IOException; import java.util.*; public abstract class XmlElementStorage implements StateStorage, Disposable { - @NonNls private static final Set OBSOLETE_COMPONENT_NAMES = new HashSet(Arrays.asList( - "Palette" - )); private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.XmlElementStorage"); - @NonNls private static final String COMPONENT = "component"; @NonNls private static final String ATTR_NAME = "name"; - @NonNls private static final String NAME = ATTR_NAME; protected TrackingPathMacroSubstitutor myPathMacroSubstitutor; @NotNull private final String myRootElementName; @@ -530,7 +521,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { private Map loadVersions(Document copy) { THashMap result = new THashMap(); - List list = copy.getRootElement().getChildren(COMPONENT); + List list = copy.getRootElement().getChildren(StorageData.COMPONENT); for (Object o : list) { if (o instanceof Element) { Element component = (Element)o; @@ -552,191 +543,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { myDisposed = true; } - protected static class StorageData { - private final Map myComponentStates; - protected final String myRootElementName; - private Integer myHash; - - public StorageData(final String rootElementName) { - myComponentStates = new THashMap(); - myRootElementName = rootElementName; - } - - protected StorageData(StorageData storageData) { - myRootElementName = storageData.myRootElementName; - myComponentStates = new THashMap(storageData.myComponentStates); - } - - protected void load(@NotNull Element rootElement) throws IOException { - final Element[] elements = JDOMUtil.getElements(rootElement); - for (Element element : elements) { - if (element.getName().equals(COMPONENT)) { - final String name = element.getAttributeValue(NAME); - - if (name == null) { - LOG.info("Broken content in file : " + this); - continue; - } - - if (OBSOLETE_COMPONENT_NAMES.contains(name)) continue; - - element.detach(); - - if (element.getAttributes().size() > 1 || !element.getChildren().isEmpty()) { - assert element.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this; - - Element existingElement = myComponentStates.get(name); - - if (existingElement != null) { - element = mergeElements(name, element, existingElement); - } - - myComponentStates.put(name, element); - } - } - } - } - - private Element mergeElements(final String name, final Element element1, final Element element2) { - ExtensionPoint point = Extensions.getRootArea().getExtensionPoint("com.intellij.componentConfigurationMerger"); - XmlConfigurationMerger[] mergers = point.getExtensions(); - for (XmlConfigurationMerger merger : mergers) { - if (merger.getComponentName().equals(name)) { - return merger.merge(element1, element2); - } - } - return element1; - } - - @NotNull - protected Element save() { - Element rootElement = new Element(myRootElementName); - String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet()); - Arrays.sort(componentNames); - for (String componentName : componentNames) { - assert componentName != null; - final Element element = myComponentStates.get(componentName); - - if (element.getAttribute(NAME) == null) element.setAttribute(NAME, componentName); - - rootElement.addContent((Element)element.clone()); - } - - return rootElement; - } - - @Nullable - private Element getState(final String name) { - final Element e = myComponentStates.get(name); - - if (e != null) { - assert e.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this; - e.removeAttribute(NAME); - } - - return e; - } - - private void removeState(final String componentName) { - myComponentStates.remove(componentName); - clearHash(); - } - - private void setState(@NotNull final String componentName, final Element element) { - element.setName(COMPONENT); - - //componentName should be first! - final List attributes = new ArrayList(element.getAttributes()); - for (Object attribute : attributes) { - Attribute attr = (Attribute)attribute; - element.removeAttribute(attr); - } - - element.setAttribute(NAME, componentName); - - for (Object attribute : attributes) { - Attribute attr = (Attribute)attribute; - element.setAttribute(attr.getName(), attr.getValue()); - } - - myComponentStates.put(componentName, element); - clearHash(); - } - - @Override - public StorageData clone() { - return new StorageData(this); - } - - public final int getHash() { - if (myHash == null) { - myHash = computeHash(); - } - return myHash.intValue(); - } - - protected int computeHash() { - int result = 0; - - for (String name : myComponentStates.keySet()) { - result = 31*result + name.hashCode(); - result = 31*result + JDOMUtil.getTreeHash(myComponentStates.get(name)); - } - - return result; - } - - protected void clearHash() { - myHash = null; - } - - public Set getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) { - Set bothStates = new HashSet(myComponentStates.keySet()); - bothStates.retainAll(storageData.myComponentStates.keySet()); - - Set diffs = new HashSet(); - diffs.addAll(storageData.myComponentStates.keySet()); - diffs.addAll(myComponentStates.keySet()); - diffs.removeAll(bothStates); - - for (String componentName : bothStates) { - final Element e1 = myComponentStates.get(componentName); - final Element e2 = storageData.myComponentStates.get(componentName); - - // some configurations want to collapse path elements in writeExternal so make sure paths are expanded - if (substitutor != null) { - substitutor.expandPaths(e2); - } - - if (!JDOMUtil.areElementsEqual(e1, e2)) { - diffs.add(componentName); - } - } - - - return diffs; - } - - public boolean isEmpty() { - return myComponentStates.size() == 0; - } - - public boolean hasState(final String componentName) { - return myComponentStates.containsKey(componentName); - } - - public void checkUnknownMacros(TrackingPathMacroSubstitutor pathMacroSubstitutor) { - if (pathMacroSubstitutor == null) return; - - for (String componentName : myComponentStates.keySet()) { - final Set unknownMacros = StorageUtil.getMacroNames(myComponentStates.get(componentName)); - if (!unknownMacros.isEmpty()) { - pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros); - } - } - } - } - public void resetData(){ myLoadedData = null; } @@ -756,7 +562,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { if (!storageData.myComponentStates.containsKey(componentToRetain) && myStorageComponentStates.containsKey(componentToRetain)) { Element emptyElement = new Element("component"); LOG.info("Create empty component element for " + componentsToRetain); - emptyElement.setAttribute(NAME, componentToRetain); + emptyElement.setAttribute(StorageData.NAME, componentToRetain); storageData.myComponentStates.put(componentToRetain, emptyElement); } } @@ -768,13 +574,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private void filterComponentsDisabledForRoaming(final Element element, final RoamingType roamingType) { - final List components = element.getChildren(COMPONENT); + final List components = element.getChildren(StorageData.COMPONENT); List toDelete = new ArrayList(); for (Object componentObj : components) { final Element componentElement = (Element)componentObj; - final String nameAttr = componentElement.getAttributeValue(NAME); + final String nameAttr = componentElement.getAttributeValue(StorageData.NAME); if (myComponentRoamingManager.getRoamingType(nameAttr) != roamingType) { toDelete.add(componentElement); @@ -787,13 +593,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private void filterOutOfDateComponents(final Element element) { - final List components = element.getChildren(COMPONENT); + final List components = element.getChildren(StorageData.COMPONENT); List toDelete = new ArrayList(); for (Object componentObj : components) { final Element componentElement = (Element)componentObj; - final String nameAttr = componentElement.getAttributeValue(NAME); + final String nameAttr = componentElement.getAttributeValue(StorageData.NAME); if (myRemoteVersionProvider.getVersion(nameAttr) <= myLocalVersionProvider.getVersion(nameAttr)) { toDelete.add(componentElement); diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java index f01b53da5585..c8dc8ad532d9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ActionsTree.java @@ -28,13 +28,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.Gray; import com.intellij.ui.LayeredIcon; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.treeStructure.Tree; import com.intellij.ui.treeStructure.treetable.TreeTableModel; -import com.intellij.util.Alarm; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.MacTreeUI; @@ -301,14 +301,8 @@ public class ActionsTree { if (node == null) { return; } - tree.expandPath(new TreePath(((DefaultMutableTreeNode)node.getParent()).getPath())); - Alarm alarm = new Alarm(); - alarm.addRequest(new Runnable() { - public void run() { - TreeUtil.selectPath(myTree, new TreePath(node.getPath())); - } - }, 100); + TreeUtil.selectInTree(node, true, tree); } @Nullable @@ -383,24 +377,31 @@ public class ActionsTree { TreePath path = new TreePath(root.getPath()); if (myTree.isPathSelected(path)){ - mySelectionPaths.add(getPath(root)); + addPathToList(root, mySelectionPaths); } if (myTree.isExpanded(path) || root.getChildCount() == 0){ - myPathsToExpand.add(getPath(root)); + addPathToList(root, myPathsToExpand); _storePaths(root); } } + private void addPathToList(DefaultMutableTreeNode root, ArrayList list) { + String path = getPath(root); + if (!StringUtil.isEmpty(path)) { + list.add(path); + } + } + private void _storePaths(DefaultMutableTreeNode root) { ArrayList childNodes = childrenToArray(root); for (final Object childNode1 : childNodes) { DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)childNode1; TreePath path = new TreePath(childNode.getPath()); if (myTree.isPathSelected(path)) { - mySelectionPaths.add(getPath(childNode)); + addPathToList(childNode, mySelectionPaths); } if ((myTree.isExpanded(path) || childNode.getChildCount() == 0) && !childNode.isLeaf()) { - myPathsToExpand.add(getPath(childNode)); + addPathToList(childNode, myPathsToExpand); _storePaths(childNode); } } @@ -412,20 +413,17 @@ public class ActionsTree { myTree.expandPath(new TreePath(node.getPath())); } - Alarm alarm = new Alarm().setActivationComponent(myComponent); - alarm.addComponentRequest(new Runnable() { - public void run() { - final ArrayList nodesToSelect = getNodesByPaths(mySelectionPaths); - if (!nodesToSelect.isEmpty()) { - for (DefaultMutableTreeNode node : nodesToSelect) { - TreeUtil.selectNode(myTree, node); - } - } - else { - myTree.setSelectionRow(0); + if (myTree.getSelectionModel().getSelectionCount() == 0) { + final ArrayList nodesToSelect = getNodesByPaths(mySelectionPaths); + if (!nodesToSelect.isEmpty()) { + for (DefaultMutableTreeNode node : nodesToSelect) { + TreeUtil.selectInTree(node, false, myTree); } } - }, 100); + else { + myTree.setSelectionRow(0); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/Group.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/Group.java index 0ad016aa14aa..cc2202cb9dd0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/Group.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/Group.java @@ -17,8 +17,8 @@ package com.intellij.openapi.keymap.impl.ui; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.QuickList; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.keymap.KeymapGroup; +import com.intellij.openapi.util.text.StringUtil; import javax.swing.*; import java.util.ArrayList; @@ -136,6 +136,24 @@ public class Group implements KeymapGroup { } public String getActionQualifiedPath(String id) { + Group cur = myParent; + StringBuilder answer = new StringBuilder(); + + while (cur != null && !cur.isRoot()) { + answer.insert(0, cur.getName() + " | "); + + cur = cur.myParent; + } + + String suffix = calcActionQualifiedPath(id); + if (StringUtil.isEmpty(suffix)) return null; + + answer.append(suffix); + + return answer.toString(); + } + + private String calcActionQualifiedPath(String id) { for (Object child : myChildren) { if (child instanceof QuickList) { child = ((QuickList)child).getActionId(); @@ -154,7 +172,7 @@ public class Group implements KeymapGroup { } } else if (child instanceof Group) { - String path = ((Group)child).getActionQualifiedPath(id); + String path = ((Group)child).calcActionQualifiedPath(id); if (path != null) { return !isRoot() ? getName() + " | " + path : path; } @@ -168,10 +186,11 @@ public class Group implements KeymapGroup { } public String getQualifiedPath() { - StringBuffer path = new StringBuffer(64); + StringBuilder path = new StringBuilder(64); Group group = this; while (group != null && !group.isRoot()) { - path.insert(0, group.getName() + " | "); + if (path.length() > 0) path.insert(0, " | "); + path.insert(0, group.getName()); group = group.myParent; } return path.toString(); diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index 57507f41f83c..8052dec5cd3d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -26,6 +26,7 @@ import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.application.impl.ApplicationInfoImpl; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.components.StorageScheme; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; @@ -131,7 +132,7 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { @Override protected void bootstrapPicoContainer() { - Extensions.instantiateArea(PluginManager.AREA_IDEA_PROJECT, this, null); + Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); super.bootstrapPicoContainer(); final MutablePicoContainer picoContainer = getPicoContainer(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index b4814b14ed62..61dac0c65b3a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -52,27 +52,31 @@ import java.awt.event.InputEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; @SuppressWarnings({"ConstantConditions"}) public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { + @Override public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String htmlBody) { } - public static final ToolWindow HEADLESS_WINDOW = new ToolWindowEx(){ + public static final ToolWindow HEADLESS_WINDOW = new ToolWindowEx() { + @Override public boolean isActive() { return false; } + @Override public void activate(@Nullable Runnable runnable) { } + @Override public boolean isDisposed() { return false; } + @Override public boolean isVisible() { return false; } @@ -82,102 +86,133 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return new ActionCallback.Done(); } + @Override public void show(@Nullable Runnable runnable) { } + @Override public void hide(@Nullable Runnable runnable) { } + @Override public ToolWindowAnchor getAnchor() { return ToolWindowAnchor.BOTTOM; } + @Override public void setAnchor(ToolWindowAnchor anchor, @Nullable Runnable runnable) { } + @Override public boolean isSplitMode() { return false; } + @Override public void setSplitMode(final boolean isSideTool, @Nullable final Runnable runnable) { } + @Override public boolean isAutoHide() { return false; } + @Override public void setAutoHide(boolean state) { } + @Override public void setToHideOnEmptyContent(final boolean hideOnEmpty) { } + @Override public boolean isToHideOnEmptyContent() { return false; } + @Override public ToolWindowType getType() { return ToolWindowType.SLIDING; } + @Override public void setType(ToolWindowType type, @Nullable Runnable runnable) { } + @Override public Icon getIcon() { return null; } + @Override public void setIcon(Icon icon) { } + @Override public String getTitle() { return ""; } + @Override public void setTitle(String title) { } + @Override public boolean isAvailable() { return false; } + @Override public void setContentUiType(ToolWindowContentUiType type, @Nullable Runnable runnable) { } + @Override public void setDefaultContentUiType(@NotNull ToolWindowContentUiType type) { } + @Override public ToolWindowContentUiType getContentUiType() { return ToolWindowContentUiType.TABBED; } + @Override public void setAvailable(boolean available, @Nullable Runnable runnable) { } + @Override public void installWatcher(ContentManager contentManager) { } + @Override public JComponent getComponent() { return null; } + @Override public ContentManager getContentManager() { return MOCK_CONTENT_MANAGER; } - public void setDefaultState(@Nullable final ToolWindowAnchor anchor, @Nullable final ToolWindowType type, @Nullable final Rectangle floatingBounds) { + @Override + public void setDefaultState(@Nullable final ToolWindowAnchor anchor, + @Nullable final ToolWindowType type, + @Nullable final Rectangle floatingBounds) { } + @Override public void activate(@Nullable final Runnable runnable, final boolean autoFocusContents) { } + @Override public void activate(@Nullable Runnable runnable, boolean autoFocusContents, boolean forced) { } + @Override public void showContentPopup(InputEvent inputEvent) { } + @Override public ActionCallback getActivation() { return new ActionCallback.Done(); } @@ -223,8 +258,7 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { }; @NonNls private static final ContentManager MOCK_CONTENT_MANAGER = new ContentManager() { - - private final ArrayList myContents = new ArrayList(); + private final List myContents = new ArrayList(); private Content mySelected; @Override @@ -232,20 +266,60 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return new ActionCallback.Done(); } - public void addContent(@NotNull final Content content) { } + @Override + public void addContent(@NotNull final Content content) { + } + + @Override public void addContent(@NotNull Content content, int order) { myContents.add(order, content); } - public void addContent(@NotNull final Content content, final Object constraints) { } - public void addContentManagerListener(@NotNull final ContentManagerListener l) { } - public void addDataProvider(@NotNull final DataProvider provider) { } - public void addSelectedContent(@NotNull final Content content) { } - public boolean canCloseAllContents() { return false; } - public boolean canCloseContents() { return false; } - public Content findContent(final String displayName) { return null; } - public List getAdditionalPopupActions(@NotNull final Content content) { return Collections.emptyList(); } - public String getCloseActionName() { return "close"; } - public String getCloseAllButThisActionName() { return "closeallbutthis"; } + + @Override + public void addContent(@NotNull final Content content, final Object constraints) { + } + + @Override + public void addContentManagerListener(@NotNull final ContentManagerListener l) { + } + + @Override + public void addDataProvider(@NotNull final DataProvider provider) { + } + + @Override + public void addSelectedContent(@NotNull final Content content) { + } + + @Override + public boolean canCloseAllContents() { + return false; + } + + @Override + public boolean canCloseContents() { + return false; + } + + @Override + public Content findContent(final String displayName) { + return null; + } + + @Override + public List getAdditionalPopupActions(@NotNull final Content content) { + return Collections.emptyList(); + } + + @Override + public String getCloseActionName() { + return "close"; + } + + @Override + public String getCloseAllButThisActionName() { + return "closeallbutthis"; + } @Override public String getPreviousContentActionName() { @@ -257,71 +331,150 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return "next"; } - public JComponent getComponent() { return new JLabel(); } - public Content getContent(final JComponent component) { return null; } - @Nullable - public Content getContent(final int index) { return null; } - public int getContentCount() { return 0; } - @NotNull - public Content[] getContents() { return myContents.toArray(new Content[myContents.size()]); } - public int getIndexOfContent(final Content content) { return -1; } - @Nullable - public Content getSelectedContent() { return mySelected; } - @NotNull - public Content[] getSelectedContents() { return new Content[0]; } - public boolean isSelected(@NotNull final Content content) { return false; } - public void removeAllContents(final boolean dispose) { - for (Iterator iterator = myContents.iterator(); iterator.hasNext(); ) { - Content content = iterator.next(); - Disposer.dispose(content); - iterator.remove(); - } + @Override + public JComponent getComponent() { + return new JLabel(); } + + @Override + public Content getContent(final JComponent component) { + return null; + } + + @Override + @Nullable + public Content getContent(final int index) { + return null; + } + + @Override + public int getContentCount() { + return 0; + } + + @Override + @NotNull + public Content[] getContents() { + return myContents.toArray(new Content[myContents.size()]); + } + + @Override + public int getIndexOfContent(final Content content) { + return -1; + } + + @Override + @Nullable + public Content getSelectedContent() { + return mySelected; + } + + @Override + @NotNull + public Content[] getSelectedContents() { + return new Content[0]; + } + + @Override + public boolean isSelected(@NotNull final Content content) { + return false; + } + + @Override + public void removeAllContents(final boolean dispose) { + for (int i = myContents.size() - 1; i >= 0; i--) { + Content content = myContents.get(i); + removeContent(content, true); + } + mySelected = null; + } + + @Override public boolean removeContent(@NotNull final Content content, final boolean dispose) { Disposer.dispose(content); + if (mySelected == content) { + mySelected = null; + } return myContents.remove(content); } + @Override public ActionCallback removeContent(@NotNull Content content, boolean dispose, boolean trackFocus, boolean implicitFocus) { return new ActionCallback.Done(); } - public void removeContentManagerListener(@NotNull final ContentManagerListener l) { } - public void removeFromSelection(@NotNull final Content content) { } - public ActionCallback selectNextContent() { return new ActionCallback.Done();} - public ActionCallback selectPreviousContent() { return new ActionCallback.Done();} - public void setSelectedContent(@NotNull final Content content) { mySelected = content; } - public ActionCallback setSelectedContentCB(@NotNull Content content) { return new ActionCallback.Done(); } - public void setSelectedContent(@NotNull final Content content, final boolean requestFocus) { } - public ActionCallback setSelectedContentCB(@NotNull final Content content, final boolean requestFocus) { return new ActionCallback.Done();} + @Override + public void removeContentManagerListener(@NotNull final ContentManagerListener l) { + } + @Override + public void removeFromSelection(@NotNull final Content content) { + } + + @Override + public ActionCallback selectNextContent() { + return new ActionCallback.Done(); + } + + @Override + public ActionCallback selectPreviousContent() { + return new ActionCallback.Done(); + } + + @Override + public void setSelectedContent(@NotNull final Content content) { + mySelected = content; + } + + @Override + public ActionCallback setSelectedContentCB(@NotNull Content content) { + return new ActionCallback.Done(); + } + + @Override + public void setSelectedContent(@NotNull final Content content, final boolean requestFocus) { + } + + @Override + public ActionCallback setSelectedContentCB(@NotNull final Content content, final boolean requestFocus) { + return new ActionCallback.Done(); + } + + @Override public void setSelectedContent(@NotNull Content content, boolean requestFocus, boolean forcedFocus) { } + @Override public ActionCallback setSelectedContentCB(@NotNull final Content content, final boolean requestFocus, final boolean forcedFocus) { return new ActionCallback.Done(); } + @Override public ActionCallback setSelectedContent(@NotNull Content content, boolean requestFocus, boolean forcedFocus, boolean implicit) { return new ActionCallback.Done(); } + @Override public ActionCallback requestFocus(@Nullable final Content content, final boolean forced) { - return new ActionCallback.Done(); + return new ActionCallback.Done(); } + @Override public void dispose() { removeAllContents(true); } + @Override public boolean isDisposed() { return false; } + @Override public boolean isSingleSelection() { return true; } + @Override @NotNull public ContentFactory getFactory() { return ServiceManager.getService(ContentFactory.class); @@ -337,10 +490,12 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return HEADLESS_WINDOW; } + @Override public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor) { return HEADLESS_WINDOW; } + @Override public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, @@ -350,54 +505,75 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { return HEADLESS_WINDOW; } - public ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor, Disposable parentDisposable) { + @Override + public ToolWindow registerToolWindow(@NotNull String id, + @NotNull JComponent component, + @NotNull ToolWindowAnchor anchor, + Disposable parentDisposable) { return HEADLESS_WINDOW; } + @Override public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor) { return HEADLESS_WINDOW; } - public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor, final boolean sideTool) { + @Override + public ToolWindow registerToolWindow(@NotNull final String id, + final boolean canCloseContent, + @NotNull final ToolWindowAnchor anchor, + final boolean sideTool) { return HEADLESS_WINDOW; } + @Override public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor, final Disposable parentDisposable, final boolean dumbAware) { return HEADLESS_WINDOW; } + @Override public void unregisterToolWindow(@NotNull String id) { } + @Override public void activateEditorComponent() { } + @Override public boolean isEditorComponentActive() { return false; } + @Override public String[] getToolWindowIds() { return ArrayUtil.EMPTY_STRING_ARRAY; } + @Override public String getActiveToolWindowId() { return null; } + @Override public ToolWindow getToolWindow(String id) { return HEADLESS_WINDOW; } + @Override public void invokeLater(Runnable runnable) { } + @Override public IdeFocusManager getFocusManager() { return IdeFocusManagerHeadless.INSTANCE; } @Override - public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String text, @Nullable final Icon icon, + public void notifyByBalloon(@NotNull final String toolWindowId, + @NotNull final MessageType type, + @NotNull final String text, + @Nullable final Icon icon, @Nullable final HyperlinkListener listener) { } @@ -411,41 +587,52 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } + @Override public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { } + @Override public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { } + @Override public String getLastActiveToolWindowId() { return null; } + @Override public String getLastActiveToolWindowId(Condition condition) { return null; } + @Override public DesktopLayout getLayout() { return new DesktopLayout(); } + @Override public void setLayoutToRestoreLater(DesktopLayout layout) { } + @Override public DesktopLayout getLayoutToRestoreLater() { return new DesktopLayout(); } + @Override public void setLayout(@NotNull DesktopLayout layout) { } + @Override public void clearSideStack() { } + @Override public void hideToolWindow(@NotNull final String id, final boolean hideSide) { } + @Override public List getIdsOn(@NotNull final ToolWindowAnchor anchor) { return new ArrayList(); } diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index 5fc42bf8fd4d..bd349fc19f2c 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.impl.ShadowBorderPainter; import com.intellij.openapi.ui.popup.Balloon; @@ -34,7 +35,6 @@ import com.intellij.openapi.wm.FocusRequestor; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.IdeGlassPaneUtil; import com.intellij.openapi.wm.impl.IdeGlassPaneEx; -import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.Wrapper; diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index d49cf30fc54c..934b3cf961f7 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -144,7 +144,9 @@ inspection.visibility.compose.suggestion=Can be {0} inspection.visibility.accept.quickfix=Accept Suggested Access Level inspection.field.can.be.local.display.name=Field can be local inspection.field.can.be.local.problem.descriptor=Field can be converted to a local variable -inspection.field.can.be.local.quickfix=Convert to local +inspection.parameter.can.be.local.display.name=Parameter can be local +inspection.parameter.can.be.local.problem.descriptor=Parameter can be converted to a local variable +inspection.convert.to.local.quickfix=Convert to local inspection.unused.return.value.display.name=Unused method return value inspection.unused.return.value.problem.descriptor=Return value of the method is never used @@ -648,4 +650,4 @@ inspection.javadoc.problem.pointing.to.itself=Javadoc pointing to itself inspection.redirect.template=Injected element has problem: {0} (in {3}). nothing.found=Nothing found -special.annotations.list.annotation.pattern=Add Annotations Pattern +special.annotations.list.annotation.pattern=Add Annotations Pattern \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 14f36537edae..cc8a5ac0a742 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -100,7 +100,7 @@ + serviceImplementation="com.intellij.openapi.roots.impl.libraries.ExportableApplicationLibraryTable"/> + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 92cbadf77359..fcb9bf2f7833 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -134,4 +134,6 @@ + + diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index c65c390c7557..733ca23c4ee6 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -33,4 +33,5 @@ + diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 6465f1f168f9..834e6e03ed0c 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -404,7 +404,7 @@ - + + diff --git a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java index e25ae7ab4100..07b3e10b0f49 100644 --- a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java @@ -18,6 +18,10 @@ package com.intellij.core; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.UsefulTestCase; @@ -32,11 +36,21 @@ public class CoreModuleManagerTest extends UsefulTestCase { public void _testLoadingModules() throws IOException, JDOMException { CoreEnvironment env = new CoreEnvironment(getTestRootDisposable()); ProjectModelEnvironment.register(env); - final String projectPath = PathManagerEx.getTestDataPath("/compileServer/incremental/annotations/addAnnotationTarget"); + final String projectPath = PathManagerEx.getTestDataPath("/core/loadingTest"); VirtualFile vFile = StandardFileSystems.local().findFileByPath(projectPath); CoreProjectLoader.loadProject(env.getProject(), vFile); final ModuleManager moduleManager = ModuleManager.getInstance(env.getProject()); final Module[] modules = moduleManager.getModules(); assertEquals(1, modules.length); + + ModuleRootManager rootManager = ModuleRootManager.getInstance(modules[0]); + final ContentEntry[] contentEntries = rootManager.getContentEntries(); + assertEquals(1, contentEntries.length); + assertNotNull(contentEntries [0].getFile()); + + final OrderEntry[] orderEntries = rootManager.getOrderEntries(); + assertEquals(2, orderEntries.length); + LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) orderEntries[1]; + assertNotNull(libraryOrderEntry.getLibrary()); } } diff --git a/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java index 84e06a1f9d02..cff8a1c275ac 100644 --- a/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java @@ -1,17 +1,27 @@ /* - * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. - * Use is subject to license terms. + * 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.run; import com.intellij.application.options.PathMacrosCollector; import com.intellij.application.options.PathMacrosImpl; -import com.intellij.util.NotNullFunction; +import com.intellij.openapi.application.PathMacroFilter; import junit.framework.TestCase; import org.jdom.Attribute; import org.jdom.Element; import org.jdom.Text; -import org.jetbrains.annotations.NotNull; import java.util.Set; @@ -32,7 +42,7 @@ public class PathMacrosCollectorTest extends TestCase { root.addContent(new Text("$c:\\a\\b\\c$ ")); root.addContent(new Text("$Revision 1.23$")); - final Set macros = PathMacrosCollector.getMacroNames(root, null, null, new PathMacrosImpl()); + final Set macros = PathMacrosCollector.getMacroNames(root, null, new PathMacrosImpl()); assertEquals(5, macros.size()); assertTrue(macros.contains("MACro1")); @@ -48,13 +58,12 @@ public class PathMacrosCollectorTest extends TestCase { configuration.setAttribute("value", "some text$macro5$fdsjfhdskjfsd$MACRO$"); root.addContent(configuration); - final Set macros = PathMacrosCollector.getMacroNames(root, null, new NotNullFunction() { - @Override - @NotNull - public Boolean fun(Object o) { - return (o instanceof Attribute) && "value".equals(((Attribute)o).getName()); - } - }, new PathMacrosImpl()); + final Set macros = PathMacrosCollector.getMacroNames(root, new PathMacroFilter() { + @Override + public boolean recursePathMacros(Attribute attribute) { + return "value".equals(attribute.getName()); + } + }, new PathMacrosImpl()); assertEquals(2, macros.size()); assertTrue(macros.contains("macro5")); @@ -68,19 +77,17 @@ public class PathMacrosCollectorTest extends TestCase { testTag.setAttribute("ignore", "$PATH$"); root.addContent(testTag); - final Set macros = PathMacrosCollector.getMacroNames(root, null, null, new PathMacrosImpl()); + final Set macros = PathMacrosCollector.getMacroNames(root, null, new PathMacrosImpl()); assertEquals(2, macros.size()); assertTrue(macros.contains("MACRO")); assertTrue(macros.contains("PATH")); - final Set filtered = PathMacrosCollector.getMacroNames(root, new NotNullFunction() { - @Override - @NotNull - public Boolean fun(Object o) { - if (o instanceof Attribute && "ignore".equals(((Attribute)o).getName())) return false; - return true; - } - }, null, new PathMacrosImpl()); + final Set filtered = PathMacrosCollector.getMacroNames(root, new PathMacroFilter() { + @Override + public boolean skipPathMacros(Attribute attribute) { + return "ignore".equals(attribute.getName()); + } + }, new PathMacrosImpl()); assertEquals(1, filtered.size()); assertTrue(macros.contains("MACRO")); diff --git a/platform/projectModel-api/src/com/intellij/openapi/application/PathMacroFilter.java b/platform/projectModel-api/src/com/intellij/openapi/application/PathMacroFilter.java new file mode 100644 index 000000000000..eebacf597505 --- /dev/null +++ b/platform/projectModel-api/src/com/intellij/openapi/application/PathMacroFilter.java @@ -0,0 +1,45 @@ +/* + * 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.openapi.application; + +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jdom.Attribute; +import org.jdom.Text; + +/** + * Allows to disable expansion of path macros in the values of certain properties. + * + * @author yole + */ +public abstract class PathMacroFilter { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.pathMacroFilter"); + + public boolean skipPathMacros(Text element) { + return false; + } + + public boolean skipPathMacros(Attribute attribute) { + return false; + } + + public boolean recursePathMacros(Text element) { + return false; + } + + public boolean recursePathMacros(Attribute attribute) { + return false; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/components/RoamingType.java b/platform/projectModel-api/src/com/intellij/openapi/components/RoamingType.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/components/RoamingType.java rename to platform/projectModel-api/src/com/intellij/openapi/components/RoamingType.java index 06283e04d07e..0cbf78053953 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/RoamingType.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/RoamingType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/State.java b/platform/projectModel-api/src/com/intellij/openapi/components/State.java similarity index 96% rename from platform/platform-api/src/com/intellij/openapi/components/State.java rename to platform/projectModel-api/src/com/intellij/openapi/components/State.java index 659c45d8cb5f..8278b2da68c6 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/State.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/State.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StateSplitter.java b/platform/projectModel-api/src/com/intellij/openapi/components/StateSplitter.java similarity index 95% rename from platform/platform-api/src/com/intellij/openapi/components/StateSplitter.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StateSplitter.java index 37081efcc9bb..19f7d7c52d13 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StateSplitter.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StateSplitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StateStorage.java b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java similarity index 98% rename from platform/platform-api/src/com/intellij/openapi/components/StateStorage.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java index 91ecc8faa203..120ca91b4132 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StateStorage.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StateStorageChooser.java b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorageChooser.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/components/StateStorageChooser.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StateStorageChooser.java index a284cbc0aa4c..ddcd7aef9087 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StateStorageChooser.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorageChooser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StateStorageOperation.java b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorageOperation.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/components/StateStorageOperation.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StateStorageOperation.java index 58e905b8c56d..ebff15ba9e34 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StateStorageOperation.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorageOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/Storage.java b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java similarity index 96% rename from platform/platform-api/src/com/intellij/openapi/components/Storage.java rename to platform/projectModel-api/src/com/intellij/openapi/components/Storage.java index b3b655987dc6..e10b97755d3a 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/Storage.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java b/platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java similarity index 98% rename from platform/platform-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java index 6c1b4ffa078a..3f12b9e96227 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StorageId.java b/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java similarity index 95% rename from platform/platform-api/src/com/intellij/openapi/components/StorageId.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java index 8740cf084480..0baf9e6ebd05 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StorageId.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/StoragePathMacros.java b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java similarity index 100% rename from platform/platform-api/src/com/intellij/openapi/components/StoragePathMacros.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java diff --git a/platform/platform-api/src/com/intellij/openapi/components/StorageScheme.java b/platform/projectModel-api/src/com/intellij/openapi/components/StorageScheme.java similarity index 94% rename from platform/platform-api/src/com/intellij/openapi/components/StorageScheme.java rename to platform/projectModel-api/src/com/intellij/openapi/components/StorageScheme.java index 969c38ef53f7..259b06b36f1a 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/StorageScheme.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StorageScheme.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/platform-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java b/platform/projectModel-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java similarity index 95% rename from platform/platform-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java rename to platform/projectModel-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java index 4a3f57f5991a..a8384caef60d 100644 --- a/platform/platform-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/XmlConfigurationMerger.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java index 93587c9e380f..0c97fd608661 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java +++ b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java @@ -16,6 +16,7 @@ package com.intellij.openapi.projectRoots; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.util.messages.Topic; import org.jetbrains.annotations.Nullable; @@ -39,10 +40,27 @@ public abstract class ProjectJdkTable { public abstract List getSdksOfType(SdkTypeId type); @Nullable - public abstract Sdk findMostRecentSdkOfType(SdkTypeId type); + public Sdk findMostRecentSdkOfType(final SdkTypeId type) { + return findMostRecentSdk(new Condition() { + public boolean value(Sdk sdk) { + return sdk.getSdkType() == type; + } + }); + } @Nullable - public abstract Sdk findMostRecentSdk(Condition condition); + public Sdk findMostRecentSdk(Condition condition) { + Sdk found = null; + for (Sdk each : getAllJdks()) { + if (!condition.value(each)) continue; + if (found == null) { + found = each; + continue; + } + if (Comparing.compare(each.getVersionString(), found.getVersionString()) > 0) found = each; + } + return found; + } public abstract void addJdk(Sdk jdk); @@ -70,6 +88,8 @@ public abstract class ProjectJdkTable { public abstract SdkTypeId getDefaultSdkType(); + public abstract SdkTypeId getSdkTypeByName(String name); + public abstract Sdk createSdk(final String name, final SdkTypeId sdkType); public static Topic JDK_TABLE_TOPIC = Topic.create("Project JDK table", Listener.class); diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java similarity index 94% rename from platform/lang-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java rename to platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java index 70572dc172e3..0e17395954fd 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java +++ b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectRootListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/SdkTypeId.java b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/SdkTypeId.java index 895b321f7d72..b4ff27528aab 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/SdkTypeId.java +++ b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/SdkTypeId.java @@ -15,9 +15,20 @@ */ package com.intellij.openapi.projectRoots; +import org.jdom.Element; +import org.jetbrains.annotations.Nullable; + /** * @author yole */ public interface SdkTypeId { String getName(); + + @Nullable + String getVersionString(Sdk sdk); + + void saveAdditionalData(SdkAdditionalData additionalData, Element additional); + + @Nullable + SdkAdditionalData loadAdditionalData(Sdk currentSdk, Element additional); } diff --git a/platform/platform-impl/src/com/intellij/application/options/PathMacrosCollector.java b/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosCollector.java similarity index 83% rename from platform/platform-impl/src/com/intellij/application/options/PathMacrosCollector.java rename to platform/projectModel-impl/src/com/intellij/application/options/PathMacrosCollector.java index 79f980fb684b..5ea334b17530 100644 --- a/platform/platform-impl/src/com/intellij/application/options/PathMacrosCollector.java +++ b/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosCollector.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,11 @@ */ package com.intellij.application.options; +import com.intellij.openapi.application.PathMacroFilter; import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.CompositePathMacroFilter; import com.intellij.openapi.components.PathMacroMap; -import com.intellij.util.NotNullFunction; +import com.intellij.openapi.extensions.Extensions; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,9 +45,15 @@ public class PathMacrosCollector extends PathMacroMap { myMatcher = MACRO_PATTERN.matcher(""); } - public static Set getMacroNames(Element root, @Nullable final NotNullFunction filter, @Nullable final NotNullFunction recursiveFilter, @NotNull final PathMacros pathMacros) { + @NotNull + public static Set getMacroNames(@NotNull final Element e) { + return getMacroNames(e, new CompositePathMacroFilter(Extensions.getExtensions(PathMacroFilter.EP_NAME)), + PathMacros.getInstance()); + } + + public static Set getMacroNames(Element root, @Nullable PathMacroFilter filter, @NotNull final PathMacros pathMacros) { final PathMacrosCollector collector = new PathMacrosCollector(); - collector.substitute(root, true, false, filter, recursiveFilter); + collector.substitute(root, true, false, filter); final HashSet result = new HashSet(collector.myMacroMap.keySet()); result.removeAll(pathMacros.getSystemMacroNames()); result.removeAll(pathMacros.getLegacyMacroNames()); @@ -54,10 +62,6 @@ public class PathMacrosCollector extends PathMacroMap { return result; } - public static Set getMacroNames(Element root, @Nullable final NotNullFunction filter, @Nullable final NotNullFunction recursiveFilter) { - return getMacroNames(root, filter, recursiveFilter, PathMacros.getInstance()); - } - @Override public String substituteRecursively(String text, boolean caseSensitive) { if (text == null || text.length() == 0) return text; @@ -93,5 +97,4 @@ public class PathMacrosCollector extends PathMacroMap { return text; } - } diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java index 544d79398992..3f7130ae2995 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java @@ -17,9 +17,21 @@ package com.intellij.core; import com.intellij.mock.MockComponentManager; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.ExtensionAreas; +import com.intellij.openapi.components.PathMacroManager; +import com.intellij.openapi.components.impl.ModulePathMacroManager; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.impl.ModuleEx; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleExtension; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; +import com.intellij.openapi.roots.impl.ProjectRootManagerImpl; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; @@ -34,6 +46,22 @@ public class CoreModule extends MockComponentManager implements ModuleEx { super(project.getPicoContainer(), parentDisposable); myProject = project; myPath = moduleFilePath; + + Extensions.instantiateArea(ExtensionAreas.IDEA_MODULE, this, null); + CoreEnvironment.registerExtensionPoint(Extensions.getArea(this), ModuleExtension.EP_NAME, ModuleExtension.class); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + Extensions.disposeArea(CoreModule.this); + } + }); + + ModuleRootManagerImpl moduleRootManager = new ModuleRootManagerImpl(this, + DirectoryIndex.getInstance(project), + ProjectRootManagerImpl.getInstanceImpl(project), + VirtualFilePointerManager.getInstance()); + getPicoContainer().registerComponentInstance(ModuleRootManager.class, moduleRootManager); + getPicoContainer().registerComponentInstance(PathMacroManager.class, new ModulePathMacroManager(PathMacros.getInstance(), this)); } @Override diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java b/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java index 1f046f914c58..28c41bac4e1f 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java @@ -16,9 +16,18 @@ package com.intellij.core; import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.StateStorageException; +import com.intellij.openapi.components.impl.stores.StorageData; import com.intellij.openapi.module.impl.ModuleEx; import com.intellij.openapi.module.impl.ModuleManagerImpl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.vfs.StandardFileSystems; +import com.intellij.openapi.vfs.VirtualFile; +import org.jdom.Element; +import org.jdom.JDOMException; import java.io.IOException; @@ -40,7 +49,22 @@ public class CoreModuleManager extends ModuleManagerImpl { @Override protected ModuleEx createAndLoadModule(String filePath) throws IOException { - return new CoreModule(myParentDisposable, myProject, filePath); + final CoreModule module = new CoreModule(myParentDisposable, myProject, filePath); + VirtualFile vFile = StandardFileSystems.local().findFileByPath(filePath); + try { + StorageData storageData = CoreProjectLoader.loadStorageFile(module, vFile); + final Element element = storageData.getState("NewModuleRootManager"); + ModuleRootManagerImpl.ModuleRootManagerState state = new ModuleRootManagerImpl.ModuleRootManagerState(); + state.readExternal(element); + ((ModuleRootManagerImpl) ModuleRootManager.getInstance(module)).loadState(state); + } + catch (JDOMException e) { + throw new StateStorageException(e); + } + catch (InvalidDataException e) { + throw new StateStorageException(e); + } + return module; } protected void deliverPendingEvents() { diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreProjectJdkTable.java b/platform/projectModel-impl/src/com/intellij/core/CoreProjectJdkTable.java new file mode 100644 index 000000000000..864f4183cae6 --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/core/CoreProjectJdkTable.java @@ -0,0 +1,86 @@ +/* + * 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.core; + +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkTypeId; + +import java.util.Collections; +import java.util.List; + +/** + * @author yole + */ +public class CoreProjectJdkTable extends ProjectJdkTable { + @Override + public Sdk findJdk(String name) { + return null; + } + + @Override + public Sdk findJdk(String name, String type) { + return null; + } + + @Override + public Sdk[] getAllJdks() { + return new Sdk[0]; + } + + @Override + public List getSdksOfType(SdkTypeId type) { + return Collections.emptyList(); + } + + @Override + public void addJdk(Sdk jdk) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeJdk(Sdk jdk) { + throw new UnsupportedOperationException(); + } + + @Override + public void updateJdk(Sdk originalJdk, Sdk modifiedJdk) { + throw new UnsupportedOperationException(); + } + + @Override + public void addListener(Listener listener) { + } + + @Override + public void removeListener(Listener listener) { + } + + @Override + public SdkTypeId getDefaultSdkType() { + return CoreSdkType.INSTANCE; + } + + @Override + public SdkTypeId getSdkTypeByName(String name) { + return CoreSdkType.INSTANCE; + } + + @Override + public Sdk createSdk(String name, SdkTypeId sdkType) { + throw new UnsupportedOperationException(); + } +} diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java b/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java index fce55cef8e93..4751b1f8811a 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java @@ -16,16 +16,21 @@ package com.intellij.core; import com.intellij.mock.MockProject; +import com.intellij.openapi.components.ComponentManager; import com.intellij.openapi.components.PathMacroManager; +import com.intellij.openapi.components.impl.stores.DirectoryStorageData; +import com.intellij.openapi.components.impl.stores.StorageData; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.io.fs.FileSystem; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -48,25 +53,32 @@ public class CoreProjectLoader { private static void loadDirectoryProject(Project project, VirtualFile projectDir) throws IOException, JDOMException { VirtualFile dotIdea = projectDir.findChild(".idea"); VirtualFile modulesXml = dotIdea.findChild("modules.xml"); - final Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(modulesXml.contentsToByteArray())); - final Element moduleManagerState = getComponentState(document, "ProjectModuleManager"); - PathMacroManager.getInstance(project).expandPaths(moduleManagerState); + StorageData storageData = loadStorageFile(project, modulesXml); + final Element moduleManagerState = storageData.getState("ProjectModuleManager"); if (moduleManagerState == null) { throw new JDOMException("cannot find ProjectModuleManager state in modules.xml"); } final CoreModuleManager moduleManager = (CoreModuleManager)ModuleManager.getInstance(project); moduleManager.loadState(moduleManagerState); + + VirtualFile libraries = dotIdea.findChild("libraries"); + if (libraries != null) { + DirectoryStorageData data = new DirectoryStorageData(); + data.loadFrom(FileSystem.FILE_SYSTEM.createFile(libraries.getPath()), + PathMacroManager.getInstance(project).createTrackingSubstitutor()); + final Element libraryTable = data.getMergedState("libraryTable", Element.class, new ProjectLibraryTable.LibraryStateSplitter(), null); + ((LibraryTableBase) ProjectLibraryTable.getInstance(project)).loadState(libraryTable); + } + moduleManager.loadModules(); } - @Nullable - private static Element getComponentState(Document document, String componentName) { - final Element[] elements = JDOMUtil.getElements(document.getRootElement()); - for (Element element : elements) { - if (element.getName().equals("component") && componentName.equals(element.getAttributeValue("name"))) { - return element; - } - } - return null; + public static StorageData loadStorageFile(ComponentManager componentManager, VirtualFile modulesXml) throws JDOMException, IOException { + final Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(modulesXml.contentsToByteArray())); + StorageData storageData = new StorageData("project"); + final Element element = document.getRootElement(); + PathMacroManager.getInstance(componentManager).expandPaths(element); + storageData.load(element); + return storageData; } } diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreSdkType.java b/platform/projectModel-impl/src/com/intellij/core/CoreSdkType.java new file mode 100644 index 000000000000..3beedf6cc5ba --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/core/CoreSdkType.java @@ -0,0 +1,50 @@ +/* + * 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.core; + +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkAdditionalData; +import com.intellij.openapi.projectRoots.SdkTypeId; +import org.jdom.Element; + +/** + * @author yole + */ +public class CoreSdkType implements SdkTypeId { + private CoreSdkType() { + } + + public static CoreSdkType INSTANCE = new CoreSdkType(); + + @Override + public String getName() { + return ""; + } + + @Override + public String getVersionString(Sdk sdk) { + return ""; + } + + @Override + public void saveAdditionalData(SdkAdditionalData additionalData, Element additional) { + } + + @Override + public SdkAdditionalData loadAdditionalData(Sdk currentSdk, Element additional) { + return null; + } +} diff --git a/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java b/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java index 1c477a07814f..9295351ef723 100644 --- a/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java +++ b/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java @@ -16,19 +16,45 @@ package com.intellij.core; import com.intellij.application.options.PathMacrosImpl; +import com.intellij.mock.MockProject; +import com.intellij.openapi.application.PathMacroFilter; import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.components.impl.ProjectPathMacroManager; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.impl.*; +import com.intellij.openapi.roots.impl.libraries.ApplicationLibraryTable; +import com.intellij.openapi.roots.impl.libraries.LibraryTablesRegistrarImpl; +import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; /** * @author yole */ public class ProjectModelEnvironment { public static void register(CoreEnvironment env) { + Extensions.registerAreaClass(ExtensionAreas.IDEA_MODULE, null); PathMacrosImpl pathMacros = new PathMacrosImpl(); env.registerApplicationComponent(PathMacros.class, pathMacros); - env.registerProjectComponent(ModuleManager.class, new CoreModuleManager(env.getProject(), env.getParentDisposable())); - env.registerProjectComponent(PathMacroManager.class, new ProjectPathMacroManager(pathMacros, env.getProject())); + CoreEnvironment.registerApplicationExtensionPoint(OrderRootType.EP_NAME, OrderRootType.class); + CoreEnvironment.registerApplicationExtensionPoint(SdkFinder.EP_NAME, SdkFinder.class); + CoreEnvironment.registerApplicationExtensionPoint(PathMacroFilter.EP_NAME, PathMacroFilter.class); + env.getApplication().registerService(ProjectJdkTable.class, new CoreProjectJdkTable()); + env.getApplication().registerService(ApplicationLibraryTable.class, new ApplicationLibraryTable()); + env.getApplication().registerService(LibraryTablesRegistrar.class, new LibraryTablesRegistrarImpl()); + + final MockProject project = env.getProject(); + env.registerProjectComponent(ModuleManager.class, new CoreModuleManager(project, env.getParentDisposable())); + env.registerProjectComponent(PathMacroManager.class, new ProjectPathMacroManager(pathMacros, project)); + env.registerProjectExtensionPoint(DirectoryIndexExcludePolicy.EP_NAME, DirectoryIndexExcludePolicy.class); + DirectoryIndex index = new DirectoryIndexImpl(project); + env.registerProjectComponent(DirectoryIndex.class, index); + env.registerProjectComponent(ProjectRootManager.class, new ProjectRootManagerImpl(project, index)); + project.registerService(ProjectLibraryTable.class, new ProjectLibraryTable()); } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java b/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java new file mode 100644 index 000000000000..ae134d493fb2 --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/CompositePathMacroFilter.java @@ -0,0 +1,63 @@ +/* + * 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.openapi.components; + +import com.intellij.openapi.application.PathMacroFilter; +import org.jdom.Attribute; +import org.jdom.Text; + +/** + * @author yole + */ +public class CompositePathMacroFilter extends PathMacroFilter { + private final PathMacroFilter[] myFilters; + + public CompositePathMacroFilter(PathMacroFilter[] filters) { + myFilters = filters; + } + + @Override + public boolean skipPathMacros(Text element) { + for (PathMacroFilter filter : myFilters) { + if (filter.skipPathMacros(element)) return true; + } + return false; + } + + @Override + public boolean skipPathMacros(Attribute attribute) { + for (PathMacroFilter filter : myFilters) { + if (filter.skipPathMacros(attribute)) return true; + } + return false; + } + + @Override + public boolean recursePathMacros(Text element) { + for (PathMacroFilter filter : myFilters) { + if (filter.recursePathMacros(element)) return true; + } + return false; + } + + @Override + public boolean recursePathMacros(Attribute attribute) { + for (PathMacroFilter filter : myFilters) { + if (filter.recursePathMacros(attribute)) return true; + } + return false; + } +} diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroMap.java b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroMap.java index 333a035a18cb..12ab9fe2ec44 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroMap.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroMap.java @@ -15,9 +15,9 @@ */ package com.intellij.openapi.components; +import com.intellij.openapi.application.PathMacroFilter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.NotNullFunction; import org.jdom.Attribute; import org.jdom.Comment; import org.jdom.Element; @@ -57,20 +57,19 @@ public abstract class PathMacroMap { } public final void substitute(Element e, boolean caseSensitive, final boolean recursively, - @Nullable final NotNullFunction filter, - @Nullable final NotNullFunction recursiveFilter) { + @Nullable PathMacroFilter filter) { List content = e.getContent(); //noinspection ForLoopReplaceableByForEach for (int i = 0, contentSize = content.size(); i < contentSize; i++) { Object child = content.get(i); if (child instanceof Element) { Element element = (Element)child; - substitute(element, caseSensitive, recursively, filter, recursiveFilter); + substitute(element, caseSensitive, recursively, filter); } else if (child instanceof Text) { Text t = (Text)child; - if (filter == null || filter.fun(t)) { - t.setText((recursively || (recursiveFilter != null && recursiveFilter.fun(t))) + if (filter == null || !filter.skipPathMacros(t)) { + t.setText((recursively || (filter != null && filter.recursePathMacros(t))) ? substituteRecursively(t.getText(), caseSensitive) : substitute(t.getText(), caseSensitive)); } @@ -85,8 +84,8 @@ public abstract class PathMacroMap { for (int i = 0, attributesSize = attributes.size(); i < attributesSize; i++) { Object attribute1 = attributes.get(i); Attribute attribute = (Attribute)attribute1; - if (filter == null || filter.fun(attribute)) { - final String value = (recursively || (recursiveFilter != null && recursiveFilter.fun(attribute))) + if (filter == null || !filter.skipPathMacros(attribute)) { + final String value = (recursively || (filter != null && filter.recursePathMacros(attribute))) ? substituteRecursively(attribute.getValue(), caseSensitive) : substitute(attribute.getValue(), caseSensitive); attribute.setValue(value); @@ -95,7 +94,7 @@ public abstract class PathMacroMap { } public final void substitute(Element e, boolean caseSensitive, final boolean recursively) { - substitute(e, caseSensitive, recursively, null, null); + substitute(e, caseSensitive, recursively, null); } public String substituteRecursively(String text, boolean caseSensitive) { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java similarity index 99% rename from platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java rename to platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java index fc1d4b07d9cc..a9dac2cc6e5e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java new file mode 100644 index 000000000000..3f3dec981d85 --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java @@ -0,0 +1,182 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.components.impl.stores; + +import com.intellij.application.options.PathMacrosCollector; +import com.intellij.openapi.components.StateSplitter; +import com.intellij.openapi.components.TrackingPathMacroSubstitutor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PairConsumer; +import com.intellij.util.io.fs.IFile; +import gnu.trove.THashMap; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class DirectoryStorageData { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.DirectoryStorageData"); + + private Map> myStates = new HashMap>(); + private long myLastTimestamp = 0; + private DirectoryStorageData myOriginalData; + + public Set getComponentNames() { + return myStates.keySet(); + } + + public void loadFrom(IFile dir, TrackingPathMacroSubstitutor pathMacroSubstitutor) { + if (!dir.exists()) { + return; + } + final IFile[] files = dir.listFiles(); + + for (IFile file : files) { + if (!StringUtil.endsWithIgnoreCase(file.getName(), ".xml")) { + //do not load system files like .DS_Store on Mac + continue; + } + + try { + final Document document = JDOMUtil.loadDocument(file); + final Element element = document.getRootElement(); + assert element.getName().equals(StorageData.COMPONENT); + + String componentName = element.getAttributeValue(StorageData.NAME); + assert componentName != null; + + if (pathMacroSubstitutor != null) { + pathMacroSubstitutor.expandPaths(element); + + final Set unknownMacros = PathMacrosCollector.getMacroNames(element); + pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros); + } + + put(componentName, file, element, true); + } + catch (IOException e) { + LOG.info("Unable to load state", e); + } + catch (JDOMException e) { + LOG.info("Unable to load state", e); + } + } + } + + public void put(final String componentName, final IFile file, final Element element, final boolean updateTimestamp) { + LOG.assertTrue(componentName != null, String.format("Component name should not be null for file: %s", file == null ? "NULL!" : file.getPath())); + + Map stateMap = myStates.get(componentName); + if (stateMap == null) { + stateMap = new HashMap(); + myStates.put(componentName, stateMap); + } + + stateMap.put(file, element); + if (updateTimestamp) updateLastTimestamp(file); + } + + public void updateLastTimestamp(final IFile file) { + myLastTimestamp = Math.max(myLastTimestamp, file.getTimeStamp()); + if (myOriginalData != null) myOriginalData.myLastTimestamp = myLastTimestamp; + } + + public long getLastTimeStamp() { + return myLastTimestamp; + } + + public Map getAllStorageFiles() { + final Map allStorageFiles = new THashMap(); + process(new StorageDataProcessor() { + public void process(final String componentName, final IFile file, final Element element) { + allStorageFiles.put(file, file.getTimeStamp()); + } + }); + + return allStorageFiles; + } + + public void processComponent(@NotNull final String componentName, @NotNull final PairConsumer consumer) { + final Map map = myStates.get(componentName); + if (map != null) { + for (IFile file : map.keySet()) { + consumer.consume(file, map.get(file)); + } + } + } + + public void process(@NotNull final StorageDataProcessor processor) { + for (final String componentName : myStates.keySet()) { + processComponent(componentName, new PairConsumer() { + public void consume(final IFile iFile, final Element element) { + processor.process(componentName, iFile, element); + } + }); + } + } + + protected DirectoryStorageData clone() { + final DirectoryStorageData result = new DirectoryStorageData(); + result.myStates = new HashMap>(myStates); + result.myLastTimestamp = myLastTimestamp; + result.myOriginalData = this; + return result; + } + + public void clear() { + myStates.clear(); + myOriginalData = null; + } + + public boolean containsComponent(final String componentName) { + return myStates.get(componentName) != null; + } + + public void removeComponent(final String componentName) { + myStates.remove(componentName); + } + + @Nullable + public T getMergedState(String componentName, Class stateClass, StateSplitter splitter, @Nullable T mergeInto) { + final List subElements = new ArrayList(); + processComponent(componentName, new PairConsumer() { + public void consume(final IFile iFile, final Element element) { + final List children = element.getChildren(); + assert children.size() == 1 : JDOMUtil.writeElement(element, File.separator); + final Element subElement = (Element)children.get(0); + subElement.detach(); + subElements.add(subElement); + } + }); + + final Element state = new Element(StorageData.COMPONENT); + splitter.mergeStatesInto(state, subElements.toArray(new Element[subElements.size()])); + removeComponent(componentName); + + return DefaultStateSerializer.deserializeState(state, stateClass, mergeInto); + } + + interface StorageDataProcessor { + void process(String componentName, IFile file, Element element); + } +} diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java new file mode 100644 index 000000000000..7c76b1e29478 --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java @@ -0,0 +1,223 @@ +/* + * 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.openapi.components.impl.stores; + +import com.intellij.application.options.PathMacrosCollector; +import com.intellij.openapi.components.PathMacroSubstitutor; +import com.intellij.openapi.components.TrackingPathMacroSubstitutor; +import com.intellij.openapi.components.XmlConfigurationMerger; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPoint; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.util.ArrayUtil; +import gnu.trove.THashMap; +import org.jdom.Attribute; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.*; + +public class StorageData { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.StorageData"); + @NonNls public static final String COMPONENT = "component"; + @NonNls public static final String NAME = "name"; + + final Map myComponentStates; + protected final String myRootElementName; + private Integer myHash; + + public StorageData(final String rootElementName) { + myComponentStates = new THashMap(); + myRootElementName = rootElementName; + } + + StorageData(StorageData storageData) { + myRootElementName = storageData.myRootElementName; + myComponentStates = new THashMap(storageData.myComponentStates); + } + + + public void load(@NotNull Element rootElement) throws IOException { + final Element[] elements = JDOMUtil.getElements(rootElement); + for (Element element : elements) { + if (element.getName().equals(COMPONENT)) { + final String name = element.getAttributeValue(NAME); + + if (name == null) { + LOG.info("Broken content in file : " + this); + continue; + } + + element.detach(); + + if (element.getAttributes().size() > 1 || !element.getChildren().isEmpty()) { + assert element.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this; + + Element existingElement = myComponentStates.get(name); + + if (existingElement != null) { + element = mergeElements(name, element, existingElement); + } + + myComponentStates.put(name, element); + } + } + } + } + + private static Element mergeElements(final String name, final Element element1, final Element element2) { + ExtensionPoint point = Extensions.getRootArea().getExtensionPoint("com.intellij.componentConfigurationMerger"); + XmlConfigurationMerger[] mergers = point.getExtensions(); + for (XmlConfigurationMerger merger : mergers) { + if (merger.getComponentName().equals(name)) { + return merger.merge(element1, element2); + } + } + return element1; + } + + @NotNull + protected Element save() { + Element rootElement = new Element(myRootElementName); + String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet()); + Arrays.sort(componentNames); + for (String componentName : componentNames) { + assert componentName != null; + final Element element = myComponentStates.get(componentName); + + if (element.getAttribute(NAME) == null) element.setAttribute(NAME, componentName); + + rootElement.addContent((Element)element.clone()); + } + + return rootElement; + } + + @Nullable + public Element getState(final String name) { + final Element e = myComponentStates.get(name); + + if (e != null) { + assert e.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this; + e.removeAttribute(NAME); + } + + return e; + } + + void removeState(final String componentName) { + myComponentStates.remove(componentName); + clearHash(); + } + + void setState(@NotNull final String componentName, final Element element) { + element.setName(COMPONENT); + + //componentName should be first! + final List attributes = new ArrayList(element.getAttributes()); + for (Object attribute : attributes) { + Attribute attr = (Attribute)attribute; + element.removeAttribute(attr); + } + + element.setAttribute(NAME, componentName); + + for (Object attribute : attributes) { + Attribute attr = (Attribute)attribute; + element.setAttribute(attr.getName(), attr.getValue()); + } + + myComponentStates.put(componentName, element); + clearHash(); + } + + @Override + public StorageData clone() { + return new StorageData(this); + } + + public final int getHash() { + if (myHash == null) { + myHash = computeHash(); + } + return myHash.intValue(); + } + + protected int computeHash() { + int result = 0; + + for (String name : myComponentStates.keySet()) { + result = 31*result + name.hashCode(); + result = 31*result + JDOMUtil.getTreeHash(myComponentStates.get(name)); + } + + return result; + } + + protected void clearHash() { + myHash = null; + } + + public Set getDifference(final StorageData storageData, PathMacroSubstitutor substitutor) { + Set bothStates = new HashSet(myComponentStates.keySet()); + bothStates.retainAll(storageData.myComponentStates.keySet()); + + Set diffs = new HashSet(); + diffs.addAll(storageData.myComponentStates.keySet()); + diffs.addAll(myComponentStates.keySet()); + diffs.removeAll(bothStates); + + for (String componentName : bothStates) { + final Element e1 = myComponentStates.get(componentName); + final Element e2 = storageData.myComponentStates.get(componentName); + + // some configurations want to collapse path elements in writeExternal so make sure paths are expanded + if (substitutor != null) { + substitutor.expandPaths(e2); + } + + if (!JDOMUtil.areElementsEqual(e1, e2)) { + diffs.add(componentName); + } + } + + + return diffs; + } + + public boolean isEmpty() { + return myComponentStates.size() == 0; + } + + public boolean hasState(final String componentName) { + return myComponentStates.containsKey(componentName); + } + + public void checkUnknownMacros(TrackingPathMacroSubstitutor pathMacroSubstitutor) { + if (pathMacroSubstitutor == null) return; + + for (String componentName : myComponentStates.keySet()) { + final Set unknownMacros = PathMacrosCollector.getMacroNames(myComponentStates.get(componentName)); + if (!unknownMacros.isEmpty()) { + pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java similarity index 95% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java index 4212e08fe2b8..4ac61761c9c7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRoot.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java similarity index 97% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java index 1a2a69bd1477..7e8e3b249926 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/ex/ProjectRootContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java similarity index 96% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java index a6458148e4be..b5c344c3040e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/CompositeProjectRoot.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ package com.intellij.openapi.projectRoots.impl; import com.intellij.openapi.projectRoots.ex.ProjectRoot; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; @@ -53,7 +53,7 @@ class CompositeProjectRoot implements ProjectRoot { ContainerUtil.addAll(result, root.getVirtualFiles()); } - return VfsUtil.toVirtualFileArray(result); + return VfsUtilCore.toVirtualFileArray(result); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java similarity index 93% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java index 18e093676725..89bf71de3008 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java @@ -26,10 +26,7 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootProvider; import com.intellij.openapi.roots.impl.RootProviderBaseImpl; import com.intellij.openapi.util.*; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.*; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -51,7 +48,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz private final MyRootProvider myRootProvider = new MyRootProvider(); private ProjectJdkImpl myOrigin = null; private SdkAdditionalData myAdditionalData = null; - private SdkType mySdkType; + private SdkTypeId mySdkType; @NonNls public static final String ELEMENT_NAME = "name"; @NonNls public static final String ATTRIBUTE_VALUE = "value"; @NonNls public static final String ELEMENT_TYPE = "type"; @@ -64,7 +61,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz @NonNls public static final String ELEMENT_HOMEPATH = "homePath"; @NonNls private static final String ELEMENT_ADDITIONAL = "additional"; - public ProjectJdkImpl(String name, SdkType sdkType) { + public ProjectJdkImpl(String name, SdkTypeId sdkType) { mySdkType = sdkType; myRootContainer = new ProjectRootContainerImpl(true); myName = name; @@ -72,9 +69,9 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz } @NotNull - public SdkType getSdkType() { + public SdkTypeId getSdkType() { if (mySdkType == null) { - mySdkType = (SdkType)ProjectJdkTable.getInstance().getDefaultSdkType(); + mySdkType = ProjectJdkTable.getInstance().getDefaultSdkType(); } return mySdkType; } @@ -116,7 +113,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz if (myHomePath == null) { return null; } - return LocalFileSystem.getInstance().findFileByPath(myHomePath); + return StandardFileSystems.local().findFileByPath(myHomePath); } public void readExternal(Element element) throws InvalidDataException { @@ -124,7 +121,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz final Element typeChild = element.getChild(ELEMENT_TYPE); final String sdkTypeName = typeChild != null? typeChild.getAttributeValue(ATTRIBUTE_VALUE) : null; if (sdkTypeName != null) { - mySdkType = getSdkTypeByName(sdkTypeName); + mySdkType = ProjectJdkTable.getInstance().getSdkTypeByName(sdkTypeName); } final Element version = element.getChild(ELEMENT_VERSION); @@ -167,16 +164,6 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz } } - private static SdkType getSdkTypeByName(String sdkTypeName) { - final SdkType[] allSdkTypes = SdkType.getAllTypes(); - for (final SdkType type : allSdkTypes) { - if (type.getName().equals(sdkTypeName)) { - return type; - } - } - return UnknownSdkType.getInstance(sdkTypeName); - } - public void writeExternal(Element element) throws WriteExternalException { element.setAttribute(ELEMENT_VERSION, "2"); @@ -345,7 +332,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz for (ProjectRoot root : roots) { ContainerUtil.addAll(files, root.getVirtualFiles()); } - return VfsUtil.toVirtualFileArray(files); + return VfsUtilCore.toVirtualFileArray(files); } public void addRoot(VirtualFile root, OrderRootType rootType) { diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java similarity index 95% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java index 56c778826ff7..9fa2bc88d895 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootContainerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +27,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.vfs.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jdom.Element; @@ -194,9 +192,12 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot private static void setNoCopyJars(ProjectRoot root){ if (root instanceof SimpleProjectRoot){ String url = ((SimpleProjectRoot)root).getUrl(); - if (JarFileSystem.PROTOCOL.equals(VirtualFileManager.extractProtocol(url))){ + if (StandardFileSystems.JAR_PROTOCOL.equals(VirtualFileManager.extractProtocol(url))){ String path = VirtualFileManager.extractPath(url); - JarFileSystem.getInstance().setNoCopyJarForPath(path); + final VirtualFileSystem fileSystem = StandardFileSystems.jar(); + if (fileSystem instanceof JarCopyingFileSystem) { + ((JarCopyingFileSystem)fileSystem).setNoCopyJarForPath(path); + } } } else if (root instanceof CompositeProjectRoot){ diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java similarity index 99% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java index d12a6828d5c9..7444798d0229 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectRootUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java similarity index 85% rename from platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java rename to platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java index 8f8ec5ca7ef7..7064b59bfa06 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/SimpleProjectRoot.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,10 @@ import com.intellij.openapi.projectRoots.ex.ProjectRoot; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.StandardFileSystems; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.vfs.ex.http.HttpFileSystem; import com.intellij.util.PathUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -61,8 +60,8 @@ public class SimpleProjectRoot implements ProjectRoot, JDOMExternalizable { @NotNull public String getPresentableString() { String path = VirtualFileManager.extractPath(myUrl); - if (path.endsWith(JarFileSystem.JAR_SEPARATOR)) { - path = path.substring(0, path.length() - JarFileSystem.JAR_SEPARATOR.length()); + if (path.endsWith(StandardFileSystems.JAR_SEPARATOR)) { + path = path.substring(0, path.length() - StandardFileSystems.JAR_SEPARATOR.length()); } return path.replace('/', File.separatorChar); } @@ -108,7 +107,7 @@ public class SimpleProjectRoot implements ProjectRoot, JDOMExternalizable { } private boolean canHaveChildren() { - return myFile.getFileSystem() instanceof HttpFileSystem || myFile.isDirectory(); + return myFile.getFileSystem().getProtocol().equals(StandardFileSystems.HTTP_PROTOCOL) || myFile.isDirectory(); } public String getUrl() { @@ -122,12 +121,12 @@ public class SimpleProjectRoot implements ProjectRoot, JDOMExternalizable { // hack to migrate internal IDEA jdk annos dir from IDEA_PROJECT_HOME/jdkAnnotations to IDEA_PROJECT_HOME/community/java/jdkAnnotations private static String migrateJdkAnnotationsToCommunityForDevIdea(String url) { - File root = new File(VfsUtil.urlToPath(url) + "/.."); + File root = new File(VfsUtilCore.urlToPath(url) + "/.."); boolean isOldJdkAnnotations = new File(root, "community/java/jdkAnnotations").exists() && new File(root, "idea.iml").exists() && new File(root, "testData").exists(); if (isOldJdkAnnotations) { - return VfsUtil.pathToUrl(PathUtil.getCanonicalPath(VfsUtil.urlToPath(url + "/../community/java/jdkAnnotations"))); + return VfsUtilCore.pathToUrl(PathUtil.getCanonicalPath(VfsUtilCore.urlToPath(url + "/../community/java/jdkAnnotations"))); } return url; } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentFolderBaseImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentFolderBaseImpl.java index f022f621164f..07e54aab89dc 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentFolderBaseImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ContentFolderBaseImpl.java @@ -71,11 +71,13 @@ public abstract class ContentFolderBaseImpl extends RootModelComponentBase imple return url; } + @Override public VirtualFile getFile() { final VirtualFile file = myFilePointer.getFile(); return file == null || !file.isDirectory() ? null : file; } + @Override @NotNull public ContentEntry getContentEntry() { return myContentEntry; @@ -86,15 +88,18 @@ public abstract class ContentFolderBaseImpl extends RootModelComponentBase imple element.setAttribute(URL_ATTRIBUTE, myFilePointer.getUrl()); } + @Override @NotNull public String getUrl() { return myFilePointer.getUrl(); } + @Override public boolean isSynthetic() { return false; } + @Override public int compareTo(ContentFolderBaseImpl folder) { return getUrl().compareTo(folder.getUrl()); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java index 144ce1153619..ddfa00d68104 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java @@ -263,12 +263,15 @@ public class DirectoryIndexImpl extends DirectoryIndex { return info; } - void fillMapWithModuleContent(VirtualFile root, final Module module, final VirtualFile contentRoot) { + void fillMapWithModuleContent(VirtualFile root, final Module module, final VirtualFile contentRoot, @Nullable final ProgressIndicator progress) { VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { @Override protected DirectoryInfo updateInfo(VirtualFile file) { + if (progress != null) { + progress.checkCanceled(); + } if (isExcluded(contentRoot, file)) return null; if (isIgnored(file)) return null; @@ -332,7 +335,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { } for (final VirtualFile contentRoot : contentRoots) { - fillMapWithModuleContent(contentRoot, module, contentRoot); + fillMapWithModuleContent(contentRoot, module, contentRoot, progress); } } @@ -354,7 +357,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { for (SourceFolder sourceFolder : sourceFolders) { VirtualFile dir = sourceFolder.getFile(); if (dir != null) { - fillMapWithModuleSource(dir, module, sourceFolder.getPackagePrefix(), dir, sourceFolder.isTestSource()); + fillMapWithModuleSource(dir, module, sourceFolder.getPackagePrefix(), dir, sourceFolder.isTestSource(), progress); } } } @@ -364,7 +367,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { final Module module, final String packageName, final VirtualFile sourceRoot, - final boolean isTestSource) { + final boolean isTestSource, @Nullable final ProgressIndicator progress) { VfsUtilCore.visitChildrenRecursively(dir, new DirectoryVisitor() { @@ -372,6 +375,9 @@ public class DirectoryIndexImpl extends DirectoryIndex { @Override protected DirectoryInfo updateInfo(VirtualFile file) { + if (progress != null) { + progress.checkCanceled(); + } DirectoryInfo info = myDirToInfoMap.get(file); if (info == null) return null; if (!module.equals(info.module)) return null; @@ -414,13 +420,16 @@ public class DirectoryIndexImpl extends DirectoryIndex { if (isLibrary) { VirtualFile[] sourceRoots = orderEntry.getFiles(OrderRootType.SOURCES); for (final VirtualFile sourceRoot : sourceRoots) { - fillMapWithLibrarySources(sourceRoot, "", sourceRoot); + fillMapWithLibrarySources(sourceRoot, "", sourceRoot, progress); } } } } - protected void fillMapWithLibrarySources(VirtualFile dir, String packageName, VirtualFile sourceRoot) { + protected void fillMapWithLibrarySources(VirtualFile dir, String packageName, VirtualFile sourceRoot, @Nullable ProgressIndicator progress) { + if (progress != null) { + progress.checkCanceled(); + } if (isIgnored(dir)) return; DirectoryInfo info = getOrCreateDirInfo(dir); @@ -438,7 +447,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { for (VirtualFile child : children) { if (child.isDirectory()) { String childPackageName = getPackageNameForSubdir(packageName, child.getName()); - fillMapWithLibrarySources(child, childPackageName, sourceRoot); + fillMapWithLibrarySources(child, childPackageName, sourceRoot, progress); } } } @@ -452,13 +461,16 @@ public class DirectoryIndexImpl extends DirectoryIndex { if (isLibrary) { VirtualFile[] classRoots = orderEntry.getFiles(OrderRootType.CLASSES); for (final VirtualFile classRoot : classRoots) { - fillMapWithLibraryClasses(classRoot, "", classRoot); + fillMapWithLibraryClasses(classRoot, "", classRoot, progress); } } } } - protected void fillMapWithLibraryClasses(VirtualFile dir, String packageName, VirtualFile classRoot) { + protected void fillMapWithLibraryClasses(VirtualFile dir, String packageName, VirtualFile classRoot, @Nullable ProgressIndicator progress) { + if (progress != null) { + progress.checkCanceled(); + } if (isIgnored(dir)) return; DirectoryInfo info = getOrCreateDirInfo(dir); @@ -478,7 +490,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { for (VirtualFile child : children) { if (child.isDirectory()) { String childPackageName = getPackageNameForSubdir(packageName, child.getName()); - fillMapWithLibraryClasses(child, childPackageName, classRoot); + fillMapWithLibraryClasses(child, childPackageName, classRoot, progress); } } } @@ -486,7 +498,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { private void initOrderEntries(Module module, MultiMap depEntries, MultiMap libClassRootEntries, - MultiMap libSourceRootEntries) { + MultiMap libSourceRootEntries, ProgressIndicator progress) { for (OrderEntry orderEntry : getOrderEntries(module)) { if (orderEntry instanceof ModuleOrderEntry) { @@ -509,7 +521,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { VirtualFile[] sourceRoots = orderEntry.getFiles(OrderRootType.SOURCES); for (VirtualFile sourceRoot : sourceRoots) { - fillMapWithOrderEntries(sourceRoot, oneEntryList, entryModule, null, null, null); + fillMapWithOrderEntries(sourceRoot, oneEntryList, entryModule, null, null, null, progress); } } else if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { @@ -527,23 +539,23 @@ public class DirectoryIndexImpl extends DirectoryIndex { private void fillMapWithOrderEntries(MultiMap depEntries, MultiMap libClassRootEntries, - MultiMap libSourceRootEntries) { + MultiMap libSourceRootEntries, ProgressIndicator progress) { for (Map.Entry> mapEntry : depEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, null, null, null); + fillMapWithOrderEntries(vRoot, entries, null, null, null, null, progress); } for (Map.Entry> mapEntry : libClassRootEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, vRoot, null, null); + fillMapWithOrderEntries(vRoot, entries, null, vRoot, null, null, progress); } for (Map.Entry> mapEntry : libSourceRootEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, null, vRoot, null); + fillMapWithOrderEntries(vRoot, entries, null, null, vRoot, null, progress); } } @@ -578,10 +590,10 @@ public class DirectoryIndexImpl extends DirectoryIndex { protected void fillMapWithOrderEntries(final VirtualFile root, final Collection orderEntries, - final Module module, - final VirtualFile libraryClassRoot, - final VirtualFile librarySourceRoot, - final DirectoryInfo parentInfo) { + @Nullable final Module module, + @Nullable final VirtualFile libraryClassRoot, + @Nullable final VirtualFile librarySourceRoot, + @Nullable final DirectoryInfo parentInfo, @Nullable final ProgressIndicator progress) { VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { @@ -589,6 +601,9 @@ public class DirectoryIndexImpl extends DirectoryIndex { @Override protected DirectoryInfo updateInfo(VirtualFile dir) { + if (progress != null) { + progress.checkCanceled(); + } if (isIgnored(dir)) return null; DirectoryInfo info = myDirToInfoMap.get(dir); // do not create it here! @@ -659,9 +674,9 @@ public class DirectoryIndexImpl extends DirectoryIndex { initOrderEntries(module, depEntries, libClassRootEntries, - libSourceRootEntries); + libSourceRootEntries, progress); } - fillMapWithOrderEntries(depEntries, libClassRootEntries, libSourceRootEntries); + fillMapWithOrderEntries(depEntries, libClassRootEntries, libSourceRootEntries, progress); killOrderEntryArrayDuplicates(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java index 38ff2c508487..41af61287be1 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleJdkOrderEntryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package com.intellij.openapi.roots.impl; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleJdkOrderEntry; @@ -73,25 +72,16 @@ public class ModuleJdkOrderEntryImpl extends LibraryOrderEntryBaseImpl implement } } - public abstract static class SdkFinder { - private static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.sdkFinder"); - - @Nullable - public Sdk findSdk(String name, String sdkType) { - return null; - } - } - @Nullable - private static Sdk findJdk(final String jdkName, final String jdkType) { + private static Sdk findJdk(final String sdkName, final String sdkType) { for (SdkFinder sdkFinder : SdkFinder.EP_NAME.getExtensions()) { - final Sdk sdk = sdkFinder.findSdk(jdkName, jdkType); + final Sdk sdk = sdkFinder.findSdk(sdkName, sdkType); if (sdk != null) { return sdk; } } final ProjectJdkTable projectJdkTable = ProjectJdkTable.getInstance(); - return projectJdkTable.findJdk(jdkName, jdkType); + return projectJdkTable.findJdk(sdkName, sdkType); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java index 537e1607f1ec..4dbeeb3d5199 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleLibraryTable.java @@ -44,14 +44,17 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi private final RootModelImpl myRootModel; private final ProjectRootManagerImpl myProjectRootManager; public static final LibraryTablePresentation MODULE_LIBRARY_TABLE_PRESENTATION = new LibraryTablePresentation() { + @Override public String getDisplayName(boolean plural) { return ProjectBundle.message("module.library.display.name", plural ? 2 : 1); } + @Override public String getDescription() { return ProjectBundle.message("libraries.node.text.module"); } + @Override public String getLibraryTableEditorTitle() { return ProjectBundle.message("library.configure.module.title"); } @@ -62,6 +65,7 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi myProjectRootManager = projectRootManager; } + @Override @NotNull public Library[] getLibraries() { final ArrayList result = new ArrayList(); @@ -70,10 +74,12 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi return result.toArray(new Library[result.size()]); } + @Override public Library createLibrary() { return createLibrary(null); } + @Override public Library createLibrary(String name) { return createLibrary(name, null); } @@ -85,6 +91,7 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi return orderEntry.getLibrary(); } + @Override public void removeLibrary(@NotNull Library library) { final Iterator orderIterator = myRootModel.getOrderIterator(); while (orderIterator.hasNext()) { @@ -102,6 +109,7 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi } } + @Override @NotNull public Iterator getLibraryIterator() { FilteringIterator filteringIterator = @@ -109,18 +117,22 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi return new ConvertingIterator(filteringIterator, ORDER_ENTRY_TO_LIBRARY_CONVERTOR); } + @Override public String getTableLevel() { return LibraryTableImplUtil.MODULE_LEVEL; } + @Override public LibraryTablePresentation getPresentation() { return MODULE_LIBRARY_TABLE_PRESENTATION; } + @Override public boolean isEditable() { return true; } + @Override @Nullable public Library getLibraryByName(@NotNull String name) { final Iterator libraryIterator = getLibraryIterator(); @@ -131,14 +143,17 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi return null; } + @Override public void addListener(Listener listener) { throw new UnsupportedOperationException(); } + @Override public void addListener(Listener listener, Disposable parentDisposable) { throw new UnsupportedOperationException("Method addListener is not yet implemented in " + getClass().getName()); } + @Override public void removeListener(Listener listener) { throw new UnsupportedOperationException(); } @@ -149,24 +164,29 @@ public class ModuleLibraryTable implements LibraryTable, LibraryTableBase.Modifi private static class ModuleLibraryOrderEntryCondition implements Condition { + @Override public boolean value(OrderEntry entry) { return entry instanceof LibraryOrderEntry && ((LibraryOrderEntry)entry).isModuleLevel() && ((LibraryOrderEntry)entry).getLibrary() != null; } } private static class OrderEntryToLibraryConvertor implements Convertor { + @Override public Library convert(LibraryOrderEntry o) { return o.getLibrary(); } } + @Override public void commit() { } + @Override public boolean isChanged() { return myRootModel.isChanged(); } + @Override public ModifiableModel getModifiableModel() { return this; } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelComponentBase.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelComponentBase.java index 25a686e6f38f..5dc97011e512 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelComponentBase.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelComponentBase.java @@ -37,6 +37,7 @@ public abstract class RootModelComponentBase implements Disposable { return myRootModel; } + @Override public void dispose() { myDisposed = true; } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SdkFinder.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SdkFinder.java new file mode 100644 index 000000000000..7d5674a228a0 --- /dev/null +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SdkFinder.java @@ -0,0 +1,29 @@ +/* + * 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.openapi.roots.impl; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.projectRoots.Sdk; +import org.jetbrains.annotations.Nullable; + +public abstract class SdkFinder { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.sdkFinder"); + + @Nullable + public Sdk findSdk(String name, String sdkType) { + return null; + } +} diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SourceFolderImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SourceFolderImpl.java index d3d272f33429..049e7048b875 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SourceFolderImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/SourceFolderImpl.java @@ -31,7 +31,7 @@ import org.jetbrains.annotations.NotNull; */ public class SourceFolderImpl extends ContentFolderBaseImpl implements SourceFolder, ClonableContentFolder { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.SimpleSourceFolderImpl"); - private boolean myIsTestSource; + private final boolean myIsTestSource; @NonNls public static final String ELEMENT_NAME = "sourceFolder"; @NonNls public static final String TEST_SOURCE_ATTR = "isTestSource"; private String myPackagePrefix; @@ -75,14 +75,17 @@ public class SourceFolderImpl extends ContentFolderBaseImpl implements SourceFol myPackagePrefix = that.myPackagePrefix; } + @Override public boolean isTestSource() { return myIsTestSource; } + @Override public String getPackagePrefix() { return myPackagePrefix; } + @Override public void setPackagePrefix(String packagePrefix) { myPackagePrefix = packagePrefix; } @@ -95,10 +98,12 @@ public class SourceFolderImpl extends ContentFolderBaseImpl implements SourceFol } } + @Override public ContentFolder cloneFolder(ContentEntry contentEntry) { return new SourceFolderImpl(this, (ContentEntryImpl) contentEntry); } + @Override public int compareTo(ContentFolderBaseImpl folder) { if (!(folder instanceof SourceFolderImpl)) return -1; diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java similarity index 74% rename from platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java rename to platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java index a611b61cb12e..72f349ff2b70 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ApplicationLibraryTable.java @@ -16,26 +16,15 @@ package com.intellij.openapi.roots.impl.libraries; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.libraries.LibraryTablePresentation; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; -import org.jetbrains.annotations.NotNull; - -import java.io.File; /** * @author dsl */ -@State( - name = "libraryTable", - roamingType = RoamingType.DISABLED, - storages = { - @Storage( file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml") - } -) -public class ApplicationLibraryTable extends LibraryTableBase implements ExportableComponent { +public class ApplicationLibraryTable extends LibraryTableBase { private static final LibraryTablePresentation GLOBAL_LIBRARY_TABLE_PRESENTATION = new LibraryTablePresentation() { public String getDisplayName(boolean plural) { return ProjectBundle.message("global.library.display.name", plural ? 2 : 1); @@ -69,14 +58,4 @@ public class ApplicationLibraryTable extends LibraryTableBase implements Exporta public static String getExternalFileName() { return "applicationLibraries"; } - - @NotNull - public File[] getExportFiles() { - return new File[]{PathManager.getOptionsFile(getExternalFileName())}; - } - - @NotNull - public String getPresentableName() { - return ProjectBundle.message("library.global.settings"); - } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java index ed42a437fad9..0b5d61152b59 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java @@ -89,7 +89,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myRootsWatcher.updateWatchedRoots(); } - LibraryImpl(String name, final @Nullable PersistentLibraryKind kind, LibraryTable table, ModifiableRootModel rootModel) { + LibraryImpl(String name, @Nullable final PersistentLibraryKind kind, LibraryTable table, ModifiableRootModel rootModel) { myName = name; myLibraryTable = table; myRootModel = rootModel; @@ -131,20 +131,24 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myJarDirectories.copyFrom(from.myJarDirectories); } + @Override public void dispose() { assert !isDisposed(); Disposer.dispose(myRootsWatcher); myDisposed = true; } + @Override public boolean isDisposed() { return myDisposed; } + @Override public String getName() { return myName; } + @Override @NotNull public String[] getUrls(@NotNull OrderRootType rootType) { assert !isDisposed(); @@ -152,6 +156,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return result.getUrls(); } + @Override @NotNull public VirtualFile[] getFiles(@NotNull OrderRootType rootType) { assert !isDisposed(); @@ -182,18 +187,21 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { } } + @Override public void setName(String name) { LOG.assertTrue(isWritable()); myName = name; } /* you have to commit modifiable model or dispose it by yourself! */ + @Override @NotNull public ModifiableModel getModifiableModel() { assert !isDisposed(); return new LibraryImpl(this, this, myRootModel); } + @Override public Library cloneLibrary(RootModelImpl rootModel) { LOG.assertTrue(myLibraryTable == null); final LibraryImpl clone = new LibraryImpl(this, null, rootModel); @@ -201,6 +209,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return clone; } + @Override public List getInvalidRootUrls(OrderRootType type) { final List pointers = myRoots.get(type).getList(); List invalidPaths = null; @@ -221,6 +230,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myProperties = properties; } + @Override @NotNull public RootProvider getRootProvider() { return myRootProvider; @@ -241,6 +251,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return result; } + @Override public void readExternal(Element element) throws InvalidDataException { readName(element); readProperties(element); @@ -285,6 +296,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { public static List sortRootTypes(Collection rootTypes) { List allTypes = new ArrayList(rootTypes); Collections.sort(allTypes, new Comparator() { + @Override public int compare(final OrderRootType o1, final OrderRootType o2) { return getSortKey(o1).compareTo(getSortKey(o2)); } @@ -296,12 +308,13 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { if (orderRootType instanceof PersistentOrderRootType) { return ((PersistentOrderRootType)orderRootType).getSdkRootName(); } - else if (orderRootType instanceof OrderRootType.DocumentationRootType) { + if (orderRootType instanceof OrderRootType.DocumentationRootType) { return ((OrderRootType.DocumentationRootType)orderRootType).getSdkRootName(); } return ""; } + @Override public void writeExternal(Element rootElement) throws WriteExternalException { LOG.assertTrue(!isDisposed(), "Already disposed!"); @@ -357,6 +370,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myKind = kind; } + @Override public void addRoot(@NotNull String url, @NotNull OrderRootType rootType) { LOG.assertTrue(isWritable()); assert !isDisposed(); @@ -365,6 +379,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { container.add(url); } + @Override public void addRoot(@NotNull VirtualFile file, @NotNull OrderRootType rootType) { LOG.assertTrue(isWritable()); assert !isDisposed(); @@ -373,14 +388,17 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { container.add(file); } + @Override public void addJarDirectory(@NotNull final String url, final boolean recursive) { addJarDirectory(url, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } + @Override public void addJarDirectory(@NotNull final VirtualFile file, final boolean recursive) { addJarDirectory(file, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } + @Override public void addJarDirectory(@NotNull final String url, final boolean recursive, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); @@ -389,6 +407,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myJarDirectories.add(rootType, url, recursive); } + @Override public void addJarDirectory(@NotNull final VirtualFile file, final boolean recursive, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); @@ -397,20 +416,24 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { myJarDirectories.add(rootType, file.getUrl(), recursive); } + @Override public boolean isJarDirectory(@NotNull final String url) { return isJarDirectory(url, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } + @Override public boolean isJarDirectory(@NotNull final String url, @NotNull final OrderRootType rootType) { return myJarDirectories.contains(rootType, url); } + @Override public boolean isValid(@NotNull final String url, @NotNull final OrderRootType rootType) { final VirtualFilePointerContainer container = myRoots.get(rootType); final VirtualFilePointer fp = container.findByUrl(url); return fp != null && fp.isValid(); } + @Override public boolean removeRoot(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); @@ -424,6 +447,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return false; } + @Override public void moveRootUp(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); @@ -431,6 +455,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { container.moveUp(url); } + @Override public void moveRootDown(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); @@ -438,6 +463,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { container.moveDown(url); } + @Override public boolean isChanged() { return !mySource.equals(this); } @@ -471,6 +497,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return mySource; } + @Override public void commit() { assert !isDisposed(); mySource.commit(this); @@ -517,6 +544,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { } private class MyRootProviderImpl extends RootProviderBaseImpl { + @Override @NotNull public String[] getUrls(@NotNull OrderRootType rootType) { Set originalUrls = new LinkedHashSet(Arrays.asList(LibraryImpl.this.getUrls(rootType))); @@ -526,12 +554,14 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return ArrayUtil.toStringArray(originalUrls); } + @Override @NotNull public VirtualFile[] getFiles(@NotNull final OrderRootType rootType) { return LibraryImpl.this.getFiles(rootType); } } + @Override public LibraryTable getTable() { return myLibraryTable; } @@ -558,6 +588,7 @@ public class LibraryImpl implements LibraryEx.ModifiableModelEx, LibraryEx { return result; } + @NonNls @Override public String toString() { return "Library: name:" + myName + "; jars:" + myJarDirectories + "; roots:" + myRoots.values(); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java index bb03da56ec93..1e67ae55dca6 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java @@ -44,10 +44,12 @@ public abstract class LibraryTableBase implements PersistentStateComponent getLibraryIterator() { return myModel.getLibraryIterator(); } + @Override public Library getLibraryByName(@NotNull String name) { return myModel.getLibraryByName(name); } + @Override public void addListener(Listener listener) { myDispatcher.addListener(listener); } + @Override public void addListener(Listener listener, Disposable parentDisposable) { myDispatcher.addListener(listener, parentDisposable); } + @Override public void removeListener(Listener listener) { myDispatcher.removeListener(listener); } @@ -117,12 +126,14 @@ public abstract class LibraryTableBase implements PersistentStateComponent getLibraryIterator() { return Collections.unmodifiableList(myLibraries).iterator(); } + @Override @Nullable public Library getLibraryByName(@NotNull String name) { for (Library myLibrary : myLibraries) { @@ -229,6 +245,7 @@ public abstract class LibraryTableBase implements PersistentStateComponent thisLibraries = new HashSet(myLibraries); @@ -263,6 +282,7 @@ public abstract class LibraryTableBase implements PersistentStateComponent libraries = new HashMap(); for (Library library : myLibraries) { @@ -288,6 +308,7 @@ public abstract class LibraryTableBase implements PersistentStateComponent libraries = ContainerUtil.findAll(myLibraries, new Condition() { @Override diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java similarity index 98% rename from platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java rename to platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java index 80140154fe75..81ef53358b48 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTablesRegistrarImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java similarity index 99% rename from platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java rename to platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java index 4885396e373e..b5d18b37b600 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/ProjectLibraryTable.java @@ -56,9 +56,6 @@ public class ProjectLibraryTable extends LibraryTableBase { } }; - ProjectLibraryTable() { - - } public static LibraryTable getInstance(Project project) { return ServiceManager.getService(project, ProjectLibraryTable.class); } diff --git a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java index 3a37e5b3d100..6e84ee8c0c03 100644 --- a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java +++ b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java @@ -407,7 +407,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule, private long myModificationStamp; private long getCurrentModificationStamp() { final PsiFile containingFile = getPsiFile(); - return containingFile == null ? -1L : containingFile.getModificationStamp(); + return containingFile == null ? -1L : containingFile.getViewProvider().getModificationStamp(); } @Override diff --git a/platform/util/src/com/intellij/openapi/util/Disposer.java b/platform/util/src/com/intellij/openapi/util/Disposer.java index 65ab06fd114c..7005e1fc3e3a 100644 --- a/platform/util/src/com/intellij/openapi/util/Disposer.java +++ b/platform/util/src/com/intellij/openapi/util/Disposer.java @@ -147,7 +147,7 @@ public class Disposer { } /** - * @return object registered on parentDisposable which is equal to object, or null + * @return object registered on parentDisposable which is equal to object, or null if not found */ @Nullable public static T findRegisteredObject(@NotNull Disposable parentDisposable, @NotNull T object) { diff --git a/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java b/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java index 34957b1fb0e5..1e2df377e4f2 100644 --- a/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java +++ b/platform/util/src/com/intellij/util/io/PersistentEnumeratorDelegate.java @@ -39,7 +39,11 @@ public class PersistentEnumeratorDelegate implements Closeable, Forceable @Override public void close() throws IOException { - myEnumerator.close(); + final PersistentEnumeratorBase enumerator = myEnumerator; + //noinspection ConstantConditions + if (enumerator != null) { + enumerator.close(); + } } public boolean isClosed() { diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMap.java b/platform/util/src/com/intellij/util/io/PersistentHashMap.java index ca5537669339..f1bd5d06bf37 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMap.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMap.java @@ -191,10 +191,22 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< } } catch (IOException e) { + try { + // attempt to close already opened resources + close(); + } + catch (Throwable ignored) { + } throw e; // rethrow } catch (Throwable t) { LOG.error(t); + try { + // attempt to close already opened resources + close(); + } + catch (Throwable ignored) { + } throw new PersistentEnumerator.CorruptedException(file); } } @@ -472,7 +484,10 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< try { myAppendCacheFlusher.stop(); myAppendCache.clear(); - myValueStorage.dispose(); + final PersistentHashMapValueStorage valueStorage = myValueStorage; + if (valueStorage != null) { + valueStorage.dispose(); + } } finally { super.close(); @@ -490,22 +505,26 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< myLiveAndGarbageKeysCounter = 0; myReadCompactionGarbageSize = 0; - traverseAllRecords(new PersistentEnumerator.RecordsProcessor() { - @Override - public boolean process(final int keyId) throws IOException { - final long record = readValueId(keyId); - if (record != NULL_ADDR) { - PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(record); - long value = newStorage.appendBytes(readResult.buffer, 0, readResult.buffer.length, 0); - updateValueId(keyId, value, record, null, getCurrentKey()); - myLiveAndGarbageKeysCounter += LIVE_KEY_MASK; + try { + traverseAllRecords(new PersistentEnumerator.RecordsProcessor() { + @Override + public boolean process(final int keyId) throws IOException { + final long record = readValueId(keyId); + if (record != NULL_ADDR) { + PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(record); + long value = newStorage.appendBytes(readResult.buffer, 0, readResult.buffer.length, 0); + updateValueId(keyId, value, record, null, getCurrentKey()); + myLiveAndGarbageKeysCounter += LIVE_KEY_MASK; + } + return true; } - return true; - } - }); + }); + } + finally { + newStorage.dispose(); + } myValueStorage.dispose(); - newStorage.dispose(); FileUtil.rename(new File(newPath), getDataFile(myEnumerator.myFile)); 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 629efb096a35..4bd2e96dc49b 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsConfiguration.java @@ -51,7 +51,7 @@ public final class VcsConfiguration implements PersistentStateComponent private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.VcsConfiguration"); public final static long ourMaximumFileForBaseRevisionSize = 500 * 1000; - @NonNls private static final String VALUE_ATTR = "value"; + @NonNls static final String VALUE_ATTR = "value"; @NonNls private static final String CONFIRM_MOVE_TO_FAILED_COMMIT_ELEMENT = "confirmMoveToFailedCommit"; @NonNls private static final String CONFIRM_REMOVE_EMPTY_CHANGELIST_ELEMENT = "confirmRemoveEmptyChangelist"; @@ -147,7 +147,7 @@ public final class VcsConfiguration implements PersistentStateComponent public boolean SHOW_FILE_HISTORY_AS_TREE = false; public float FILE_HISTORY_SPLITTER_PROPORTION = 0.6f; private static final int MAX_STORED_MESSAGES = 25; - @NonNls private static final String MESSAGE_ELEMENT_NAME = "MESSAGE"; + @NonNls static final String MESSAGE_ELEMENT_NAME = "MESSAGE"; private final PerformInBackgroundOption myUpdateOption = new UpdateInBackgroundOption(); private final PerformInBackgroundOption myCommitOption = new CommitInBackgroundOption(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java new file mode 100644 index 000000000000..579e031dd3cf --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsPathMacroFilter.java @@ -0,0 +1,38 @@ +/* + * 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.openapi.vcs; + +import com.intellij.openapi.application.PathMacroFilter; +import org.jdom.Attribute; +import org.jdom.Element; + +/** + * @author yole + */ +public class VcsPathMacroFilter extends PathMacroFilter { + @Override + public boolean skipPathMacros(Attribute attribute) { + final Element parent = attribute.getParent(); + final String parentName = parent.getName(); + if (VcsConfiguration.MESSAGE_ELEMENT_NAME.equals(parentName) && VcsConfiguration.VALUE_ATTR.equals(attribute.getName())) { + return true; + } + if ("option".equals(parentName) && "LAST_COMMIT_MESSAGE".equals(parent.getAttributeValue("name"))) { + return true; + } + return false; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java index eec77ea709e5..22ceca6ae259 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,12 @@ package com.intellij.openapi.vcs.changes; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.StorageScheme; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/ui/BreakpointItem.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/ui/BreakpointItem.java index b0725d8a9733..769366f94787 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/ui/BreakpointItem.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/ui/BreakpointItem.java @@ -18,11 +18,14 @@ package com.intellij.xdebugger.breakpoints.ui; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.popup.util.DetailView; import com.intellij.ui.popup.util.ItemWrapper; import com.intellij.xdebugger.ui.DebuggerColors; +import javax.swing.*; import java.awt.*; /** @@ -46,4 +49,15 @@ public abstract class BreakpointItem implements ItemWrapper { attributes.setBackgroundColor(new Color(color.getRed(), color.getGreen()-100, color.getBlue()-100)); panel.navigateInPreviewEditor(virtualFile, new LogicalPosition(line, 0), attributes); } + + @Override + public void execute(Project project, JBPopup popup) { + setEnabled(!isEnabled()); + } + + @Override + public void updateAccessoryView(JComponent component) { + final JCheckBox checkBox = (JCheckBox)component; + checkBox.setSelected(isEnabled()); + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java index b1407273955e..96891234d401 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointItem.java @@ -52,14 +52,6 @@ class XBreakpointItem extends BreakpointItem { return ((XBreakpointBase)myBreakpoint).getIcon(); } - @Override - public void updateMnemonicLabel(JLabel label) { - //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public void execute(Project project, JBPopup popup) { - } @Override public String speedSearchText() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsMasterDetailPopupFactory.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsMasterDetailPopupFactory.java index edc546a7446f..63638a7e5fb0 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsMasterDetailPopupFactory.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/BreakpointsMasterDetailPopupFactory.java @@ -26,6 +26,7 @@ import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.JBPopupListener; import com.intellij.openapi.ui.popup.LightweightWindowEvent; +import com.intellij.ui.CheckBoxListListener; import com.intellij.ui.components.JBList; import com.intellij.ui.popup.util.ItemWrapper; import com.intellij.ui.popup.util.MasterDetailPopupBuilder; @@ -48,7 +49,7 @@ import java.util.List; * Time: 3:11 AM * To change this template use File | Settings | File Templates. */ -public class BreakpointsMasterDetailPopupFactory { +public class BreakpointsMasterDetailPopupFactory implements CheckBoxListListener { private final List myBreakpointPanelProviders; private Project myProject; @@ -69,6 +70,14 @@ public class BreakpointsMasterDetailPopupFactory { }); } + @Override + public void checkBoxSelectionChanged(int index, boolean value) { + final Object o = myModel.get(index); + if (o instanceof BreakpointItem) { + ((BreakpointItem)o).setEnabled(value); + } + } + public static BreakpointsMasterDetailPopupFactory getInstance(Project project) { return ServiceManager.getService(project, BreakpointsMasterDetailPopupFactory.class); } @@ -76,7 +85,9 @@ public class BreakpointsMasterDetailPopupFactory { public JBPopup createPopup(@Nullable Object initialBreakpoint) { final DefaultListSelectionModel selectionModel = new DefaultListSelectionModel(); myModel = createBreakpointsItemsList(selectionModel); + final JBList list = new JBList(myModel); + list.setSelectionModel(selectionModel); selectInitial(initialBreakpoint, myModel, list); @@ -100,8 +111,8 @@ public class BreakpointsMasterDetailPopupFactory { //To change body of implemented methods use File | Settings | File Templates. } - public boolean hasItemsWithMnemonic(Project project) { - return false; + public JComponent createAccessoryView(Project project) { + return new JCheckBox(); } }).setCloseOnEnter(false).createMasterDetailPopup(); @@ -159,48 +170,9 @@ public class BreakpointsMasterDetailPopupFactory { } }); - actions.add(new CheckboxAction("Enabled"){ - { - registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), list); - } - @Override - public void update(AnActionEvent e) { - super.update(e); - e.getPresentation().setEnabled(list.getSelectedValue() instanceof BreakpointItem); - if (getCheckBox() != null) { - getCheckBox().setFocusable(false); - } - } - - @Override - public boolean isSelected(AnActionEvent e) { - return isSelectedBreakpointEnabled(list); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - setSelectedBreakpointEnabled(list, state); - } - }); - return actions; } - private void setSelectedBreakpointEnabled(final JBList list, boolean state) { - final Object value = list.getSelectedValue(); - if (value instanceof BreakpointItem) { - ((BreakpointItem)value).setEnabled(state); - } - } - - private boolean isSelectedBreakpointEnabled(JBList list) { - final Object value = list.getSelectedValue(); - if (value instanceof BreakpointItem) { - return ((BreakpointItem)value).isEnabled(); - } - return false; - } - private BreakpointListModel createBreakpointsItemsList(DefaultListSelectionModel selectionModel) { final BreakpointListModel model = new BreakpointListModel(); final ArrayList items = collectItems(); diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index 676a3e3f970f..ef29c4f42c0d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -20,9 +20,7 @@ import com.android.ide.common.resources.configuration.*; import com.android.sdklib.IAndroidTarget; import com.intellij.android.designer.actions.ProfileAction; import com.intellij.android.designer.componentTree.AndroidTreeDecorator; -import com.intellij.android.designer.model.ModelParser; -import com.intellij.android.designer.model.PropertyParser; -import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.android.designer.model.*; import com.intellij.android.designer.profile.ProfileManager; import com.intellij.designer.DesignerToolWindowManager; import com.intellij.designer.componentTree.TreeComponentDecorator; @@ -144,6 +142,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { RadViewComponent newRootComponent = parser.getRootComponent(); newRootComponent.setClientProperty(ModelParser.XML_FILE_KEY, myXmlFile); + newRootComponent.setClientProperty(ModelParser.MODULE_KEY, getModule()); newRootComponent.setClientProperty(TreeComponentDecorator.KEY, myTreeDecorator); PropertyParser propertyParser = new PropertyParser(myModule, myProfileAction.getProfileManager().getSelectedTarget()); @@ -441,7 +440,11 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @NotNull @Override public RadComponent create() throws Exception { - return ModelParser.createComponent(null, paletteItem.getMetaModel()); + RadViewComponent component = ModelParser.createComponent(null, paletteItem.getMetaModel()); + if (component instanceof IConfigurableComponent) { + ((IConfigurableComponent)component).configure(getModule()); + } + return component; } }; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/fragment.png b/plugins/android-designer/src/com/intellij/android/designer/icons/fragment.png new file mode 100644 index 000000000000..4e315461e7f3 Binary files /dev/null and b/plugins/android-designer/src/com/intellij/android/designer/icons/fragment.png differ diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java new file mode 100644 index 000000000000..9ec0fb74ed12 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model; + +import com.intellij.openapi.module.Module; + +/** + * @author Alexander Lobas + */ +public interface IConfigurableComponent { + void configure(Module module) throws Exception; +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java index 82b217020b22..b1740fe9f251 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java @@ -50,6 +50,7 @@ public class ModelParser extends XmlRecursiveElementVisitor { ""; public static final String XML_FILE_KEY = "XML_FILE"; + public static final String MODULE_KEY = "MODULE"; private static final int EMPTY_COMPONENT_SIZE = 5; @@ -177,7 +178,8 @@ public class ModelParser extends XmlRecursiveElementVisitor { addComponentTag(container.getTag(), newComponent, insertBefore == null ? null : insertBefore.getTag(), new Computable() { @Override public String compute() { - return newComponent.getMetaModel().getCreation(); + String creation = newComponent.getMetaModel().getCreation(); + return creation == null ? newComponent.getCreationXml() : creation; } }); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java index 08abdf217682..839ca8aca0de 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -16,10 +16,8 @@ package com.intellij.android.designer.model; import com.android.ide.common.rendering.api.ViewInfo; -import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; import com.intellij.android.designer.propertyTable.*; -import com.intellij.android.designer.propertyTable.editors.ResourceDialog; import com.intellij.designer.model.MetaManager; import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; @@ -35,7 +33,6 @@ import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.sdk.AndroidTargetData; import org.jetbrains.android.uipreview.ProjectClassLoader; import org.jetbrains.android.uipreview.RenderServiceFactory; -import org.jetbrains.annotations.NotNull; import java.util.*; @@ -50,14 +47,12 @@ public class PropertyParser { private static final String LAYOUT_PREFIX = "layout_"; private static final String LAYOUT_MARGIN_PREFIX = "layout_margin"; - private final Module myModule; private MetaManager myMetaManager; private AttributeDefinitions myDefinitions; private ProjectClassLoader myClassLoader; private Map> myCachedProperties; public PropertyParser(Module module, IAndroidTarget target) throws Exception { - myModule = module; myMetaManager = ViewsMetaManager.getInstance(module.getProject()); myCachedProperties = myMetaManager.getCache(target.hashString()); if (myCachedProperties == null) { @@ -369,9 +364,4 @@ public class PropertyParser { } return false; } - - @NotNull - public ResourceDialog createResourceDialog(ResourceType[] types) { - return new ResourceDialog(myModule, types); - } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java new file mode 100644 index 000000000000..967359d37b3c --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model; + +import com.intellij.android.designer.propertyTable.FragmentProperty; +import com.intellij.android.designer.propertyTable.IdProperty; +import com.intellij.android.designer.propertyTable.editors.FragmentDialog; +import com.intellij.android.designer.propertyTable.editors.ResourceEditor; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.editors.TextEditor; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.ui.DialogWrapper; +import org.jetbrains.android.dom.attrs.AttributeFormat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class RadFragment extends RadViewComponent implements IConfigurableComponent { + private static final Property NAME_PROPERTY = + new FragmentProperty("name", new ResourceEditor(null, Collections.emptySet(), null) { + @Override + protected void showDialog() { + Module module = myRootComponent.getClientProperty(ModelParser.MODULE_KEY); + FragmentDialog dialog = new FragmentDialog(module); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + setValue(dialog.getFragmentName()); + } + } + }); + private static final Property TAG_PROPERTY = new FragmentProperty("tag", new TextEditor()); + private static final String NAME_KEY = "fragment.name"; + + @Override + public String getCreationXml() { + return ""; + } + + @Override + public void configure(Module module) throws Exception { + FragmentDialog dialog = new FragmentDialog(module); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + setClientProperty(NAME_KEY, dialog.getFragmentName()); + } + else { + throw new Exception(); + } + } + + @Override + public void setProperties(List properties) { + if (!properties.isEmpty()) { + properties = new ArrayList(properties); + properties.add(NAME_PROPERTY); + properties.add(IdProperty.INSTANCE); + properties.add(TAG_PROPERTY); + } + super.setProperties(properties); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java similarity index 50% rename from plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java rename to plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java index d8305c0db939..fb4649c4348f 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java @@ -16,31 +16,46 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.propertyTable.IdProperty; +import com.intellij.android.designer.propertyTable.IncludeLayoutProperty; +import com.intellij.android.designer.propertyTable.editors.ResourceDialog; import com.intellij.designer.propertyTable.Property; -import org.jetbrains.android.dom.attrs.AttributeDefinition; -import org.jetbrains.android.dom.attrs.AttributeFormat; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.ui.DialogWrapper; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** * @author Alexander Lobas */ -public class RadIncludeComponent extends RadViewComponent { - private final List myProperties = new ArrayList(); +public class RadIncludeLayout extends RadViewComponent implements IConfigurableComponent { + @Override + public String getCreationXml() { + return ""; + } - public RadIncludeComponent() { - IdProperty idProperty = new IdProperty("id", new AttributeDefinition("id", Arrays.asList(AttributeFormat.Reference))); - idProperty.setImportant(true); - myProperties.add(idProperty); + public void configure(Module module) throws Exception { + ResourceDialog dialog = new ResourceDialog(module, IncludeLayoutProperty.TYPES); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + setClientProperty(IncludeLayoutProperty.NAME, dialog.getResourceName()); + } + else { + throw new Exception(); + } } @Override public void setProperties(List properties) { if (!properties.isEmpty()) { properties = new ArrayList(properties); - properties.addAll(myProperties); + properties.add(IncludeLayoutProperty.INSTANCE); + properties.add(IdProperty.INSTANCE); } super.setProperties(properties); } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index 6e81f9f11c92..a472aa3aaf51 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -61,6 +61,10 @@ public class RadViewComponent extends RadVisualComponent { } } + public String getCreationXml() { + throw new UnsupportedOperationException(); + } + public ViewInfo getViewInfo() { return myViewInfo; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 421c4cc74d9e..fad2d11dc357 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -19,16 +19,26 @@ - - + + + + + + + + @@ -37,7 +47,7 @@ + tag="view"> @@ -1398,6 +1408,10 @@ + + + + \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java index e10a2fa5e159..cf2def4a359c 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java @@ -22,7 +22,7 @@ import com.intellij.android.designer.propertyTable.renderers.ResourceRenderer; import com.intellij.designer.propertyTable.Property; import com.intellij.designer.propertyTable.PropertyEditor; import com.intellij.designer.propertyTable.PropertyRenderer; -import com.intellij.designer.propertyTable.editors.AbstractTextFieldEditor; +import com.intellij.designer.propertyTable.editors.TextEditor; import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.text.StringUtil; @@ -55,12 +55,7 @@ public class AttributeProperty extends Property { if (formats.size() == 1) { if (formats.contains(AttributeFormat.Float)) { myRenderer = new LabelPropertyRenderer(null); - myEditor = new AbstractTextFieldEditor() { - @Override - public Object getValue() throws Exception { - return myTextField.getText(); - } - }; + myEditor = new TextEditor(); } else if (formats.contains(AttributeFormat.Enum)) { myRenderer = new LabelPropertyRenderer(null); diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FragmentProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FragmentProperty.java new file mode 100644 index 000000000000..908ddfe5dd0d --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FragmentProperty.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.propertyTable; + +import com.intellij.android.designer.model.ModelParser; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class FragmentProperty extends Property { + private final String myAttribute; + private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); + private final PropertyEditor myEditor; + + public FragmentProperty(@NotNull String name, PropertyEditor editor) { + super(null, name); + myEditor = editor; + setImportant(true); + myAttribute = "android:" + name; + } + + @Override + public Property createForNewPresentation(@Nullable Property parent, @NotNull String name) { + return null; + } + + @Override + public Object getValue(RadViewComponent component) throws Exception { + String value = component.getTag().getAttributeValue(myAttribute); + return value == null ? "" : value; + } + + @Override + public void setValue(final RadViewComponent component, final Object value) throws Exception { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + if (StringUtil.isEmpty((String)value)) { + ModelParser.deleteAttribute(component, myAttribute); + } + else { + component.getTag().setAttribute(myAttribute, (String)value); + } + } + }); + } + + @Override + public boolean isDefaultValue(RadViewComponent component) throws Exception { + return component.getTag().getAttribute(myAttribute) == null; + } + + @Override + public void setDefaultValue(RadViewComponent component) throws Exception { + if (component.getTag().getAttribute(myAttribute) != null) { + setValue(component, null); + } + } + + @Override + public boolean availableFor(List components) { + return false; + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return myEditor; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IdProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IdProperty.java index a645166414b2..8c377430eb3d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IdProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IdProperty.java @@ -22,6 +22,7 @@ import com.intellij.designer.propertyTable.Property; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Pair; import org.jetbrains.android.dom.attrs.AttributeDefinition; +import org.jetbrains.android.dom.attrs.AttributeFormat; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,6 +33,13 @@ import java.util.List; * @author Alexander Lobas */ public class IdProperty extends AttributeProperty { + public static final Property INSTANCE = new IdProperty(); + + private IdProperty() { + this("id", new AttributeDefinition("id", Arrays.asList(AttributeFormat.Reference))); + setImportant(true); + } + public IdProperty(@NotNull String name, @NotNull AttributeDefinition definition) { super(name, definition); } diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java new file mode 100644 index 000000000000..68fa3fa42e4e --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.propertyTable; + +import com.android.resources.ResourceType; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.android.designer.propertyTable.editors.ResourceEditor; +import com.intellij.android.designer.propertyTable.renderers.ResourceRenderer; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.android.dom.attrs.AttributeFormat; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +/** + * @author Alexander Lobas + */ +public class IncludeLayoutProperty extends Property { + public static final String NAME = "layout:xml"; + public static ResourceType[] TYPES = new ResourceType[]{ResourceType.LAYOUT}; + private static final Set FORMATS = EnumSet.of(AttributeFormat.Reference); + public static final Property INSTANCE = new IncludeLayoutProperty(); + + private final PropertyRenderer myRenderer = new ResourceRenderer(FORMATS); + private final PropertyEditor myEditor = new ResourceEditor(TYPES, FORMATS, null); + + private IncludeLayoutProperty() { + super(null, NAME); + setImportant(true); + } + + @Override + public Property createForNewPresentation(@Nullable Property parent, @NotNull String name) { + return null; + } + + @Override + public Object getValue(RadViewComponent component) throws Exception { + String layout = component.getTag().getAttributeValue("layout"); + return layout == null ? "" : layout; + } + + @Override + public void setValue(final RadViewComponent component, final Object value) throws Exception { + if (!StringUtil.isEmpty((String)value)) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + component.getTag().setAttribute("layout", (String)value); + } + }); + } + } + + @Override + public boolean availableFor(List components) { + return false; + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return myEditor; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java new file mode 100644 index 000000000000..77d3db00a049 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.propertyTable.editors; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.ui.ListSpeedSearch; +import com.intellij.ui.ScrollPaneFactory; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.Collections; + +/** + * @author Alexander Lobas + */ +public class FragmentDialog extends DialogWrapper implements ListSelectionListener { + private final JList myList = new JList(); + private final JScrollPane myComponent = ScrollPaneFactory.createScrollPane(myList); + private String myResultFragmentName; + + public FragmentDialog(Module module) { + super(module.getProject()); + + myList.setPreferredSize(new Dimension(500, 400)); + myList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && myList.getSelectedValue() != null) { + close(OK_EXIT_CODE); + } + } + }); + + DefaultListModel model = new DefaultListModel(); + for (PsiClass psiClass : findInheritors(module, "android.app.Fragment")) { + model.addElement(psiClass.getQualifiedName()); + } + for (PsiClass psiClass : findInheritors(module, "android.support.v4.app.Fragment")) { + model.addElement(psiClass.getQualifiedName()); + } + myList.setModel(model); + + ListSelectionModel selectionModel = myList.getSelectionModel(); + selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + selectionModel.addListSelectionListener(this); + + new ListSpeedSearch(myList); + + setTitle("Fragment Dialog"); + getOKAction().setEnabled(false); + + init(); + } + + private static Collection findInheritors(Module module, String name) { + Project project = module.getProject(); + PsiClass base = JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project)); + if (base != null) { + GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); + return ClassInheritorsSearch.search(base, scope, true).findAll(); + } + return Collections.emptyList(); + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myList; + } + + @Override + protected JComponent createCenterPanel() { + return myComponent; + } + + public String getFragmentName() { + return myResultFragmentName; + } + + @Override + public void valueChanged(ListSelectionEvent e) { + myResultFragmentName = (String)myList.getSelectedValue(); + getOKAction().setEnabled(myResultFragmentName != null); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java index 350ca69a65e1..ef9bfe556bdd 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java @@ -152,10 +152,8 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen myTree.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - if (!myTreeBuilder.getSelectedElements(ResourceItem.class).isEmpty()) { - close(OK_EXIT_CODE); - } + if (e.getClickCount() == 2 && !myTreeBuilder.getSelectedElements(ResourceItem.class).isEmpty()) { + close(OK_EXIT_CODE); } } }); diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java index 835a98e3831f..bd6ccc16c2d7 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java @@ -16,10 +16,11 @@ package com.intellij.android.designer.propertyTable.editors; import com.android.resources.ResourceType; -import com.intellij.android.designer.model.PropertyParser; +import com.intellij.android.designer.model.ModelParser; import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.PropertyEditor; import com.intellij.designer.propertyTable.editors.ComboEditor; +import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.ComponentWithBrowseButton; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; @@ -38,40 +39,16 @@ import java.util.Set; * @author Alexander Lobas */ public class ResourceEditor extends PropertyEditor { - private ResourceType[] myTypes; + private final ResourceType[] myTypes; private ComponentWithBrowseButton myEditor; - private RadComponent myRootComponent; + protected RadComponent myRootComponent; public ResourceEditor(Set formats, String[] values) { - Set types = EnumSet.noneOf(ResourceType.class); - for (AttributeFormat format : formats) { - switch (format) { - case Boolean: - types.add(ResourceType.BOOL); - break; - case Color: - types.add(ResourceType.COLOR); - types.add(ResourceType.DRAWABLE); - break; - case Dimension: - types.add(ResourceType.DIMEN); - break; - case Integer: - types.add(ResourceType.INTEGER); - break; - case String: - types.add(ResourceType.STRING); - break; - case Reference: - types.add(ResourceType.COLOR); - types.add(ResourceType.DRAWABLE); - types.add(ResourceType.STRING); - types.add(ResourceType.ID); - types.add(ResourceType.STYLE); - break; - } - } - myTypes = types.toArray(new ResourceType[types.size()]); + this(convertTypes(formats), formats, values); + } + + public ResourceEditor(ResourceType[] types, Set formats, String[] values) { + myTypes = types; if (formats.contains(AttributeFormat.Enum) || formats.contains(AttributeFormat.Boolean)) { ComboboxWithBrowseButton editor = new ComboboxWithBrowseButton(); @@ -118,14 +95,7 @@ public class ResourceEditor extends PropertyEditor { myEditor.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - PropertyParser parser = myRootComponent.getClientProperty(PropertyParser.KEY); - ResourceDialog dialog = parser.createResourceDialog(myTypes); - dialog.show(); - - if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - getComboText().setText(dialog.getResourceName()); - fireValueCommitted(true, true); - } + showDialog(); } }); myEditor.addFocusListener(new FocusAdapter() { @@ -136,6 +106,39 @@ public class ResourceEditor extends PropertyEditor { }); } + private static ResourceType[] convertTypes(Set formats) { + Set types = EnumSet.noneOf(ResourceType.class); + for (AttributeFormat format : formats) { + switch (format) { + case Boolean: + types.add(ResourceType.BOOL); + break; + case Color: + types.add(ResourceType.COLOR); + types.add(ResourceType.DRAWABLE); + break; + case Dimension: + types.add(ResourceType.DIMEN); + break; + case Integer: + types.add(ResourceType.INTEGER); + break; + case String: + types.add(ResourceType.STRING); + break; + case Reference: + types.add(ResourceType.COLOR); + types.add(ResourceType.DRAWABLE); + types.add(ResourceType.STRING); + types.add(ResourceType.ID); + types.add(ResourceType.STYLE); + break; + } + } + + return types.toArray(new ResourceType[types.size()]); + } + @NotNull @Override public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { @@ -151,6 +154,26 @@ public class ResourceEditor extends PropertyEditor { return value == StringsComboEditor.UNSET || StringUtil.isEmpty(value) ? null : value; } + @Override + public void updateUI() { + SwingUtilities.updateComponentTreeUI(myEditor); + } + + protected void showDialog() { + Module module = myRootComponent.getClientProperty(ModelParser.MODULE_KEY); + ResourceDialog dialog = new ResourceDialog(module, myTypes); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + setValue(dialog.getResourceName()); + } + } + + protected final void setValue(String value) { + getComboText().setText(value); + fireValueCommitted(true, true); + } + private JTextField getComboText() { JComponent component = myEditor.getChildComponent(); if (component instanceof JTextField) { @@ -159,9 +182,4 @@ public class ResourceEditor extends PropertyEditor { JComboBox combo = (JComboBox)component; return (JTextField)combo.getEditor().getEditorComponent(); } - - @Override - public void updateUI() { - SwingUtilities.updateComponentTreeUI(myEditor); - } } \ No newline at end of file diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index f7bd8c9d1061..1a57d95de8a0 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -120,6 +120,11 @@ + + + + diff --git a/plugins/devkit/src/actions/ShuffleNamesAction.java b/plugins/devkit/src/actions/ShuffleNamesAction.java new file mode 100644 index 000000000000..5cf7dde89b25 --- /dev/null +++ b/plugins/devkit/src/actions/ShuffleNamesAction.java @@ -0,0 +1,130 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.devkit.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessorEx; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiRecursiveElementWalkingVisitor; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import gnu.trove.THashMap; + +import java.util.*; + +/** + * @author gregsh + */ +public class ShuffleNamesAction extends AnAction { + @Override + public void update(AnActionEvent e) { + Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + e.getPresentation().setEnabled(editor != null && file != null); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + if (editor == null || file == null) return; + final Project project = file.getProject(); + CommandProcessorEx commandProcessor = (CommandProcessorEx)CommandProcessorEx.getInstance(); + Object commandToken = commandProcessor.startCommand(project, e.getPresentation().getText(), e.getPresentation().getText(), UndoConfirmationPolicy.DEFAULT); + AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); + try { + shuffleIds(file, editor); + } + finally { + token.finish(); + commandProcessor.finishCommand(project, commandToken, null); + } + } + + private static boolean shuffleIds(PsiFile file, Editor editor) { + final Map map = new THashMap(); + final StringBuilder sb = new StringBuilder(); + final StringBuilder quote = new StringBuilder(); + final ArrayList split = new ArrayList(100); + file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof LeafPsiElement) { + String type = ((LeafPsiElement)element).getElementType().toString(); + String text = element.getText(); + if (text.isEmpty()) return; + + for (int i=0, len=text.length(); i 0; + boolean isNumber = false; + if (isQuoted || type.equals("ID") || type.contains("IDENT") && !"ts".equals(text) || + (isNumber = text.matches("[0-9]+"))) { + String replacement = map.get(text); + if (replacement == null) { + split.addAll(Arrays.asList((isQuoted? text.substring(quote.length(), text.length()-quote.length()).replace("''", "") : text).split(""))); + if (!isNumber) { + for (ListIterator it = split.listIterator(); it.hasNext(); ) { + String s = it.next(); + if (s.isEmpty()) { + it.remove(); + continue; + } + int c = s.charAt(0); + int cap = c & 32; + c &= ~cap; + c = (char) ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 7) % 26 + 'A') : c) | cap; + it.set(String.valueOf((char)c)); + } + } + Collections.shuffle(split); + if (isNumber && "0".equals(split.get(0))) { + split.set(0, "1"); + } + replacement = StringUtil.join(split, ""); + if (isQuoted) { + replacement = quote + replacement + quote.reverse(); + } + map.put(text, replacement); + } + text = replacement; + } + sb.append(text); + quote.setLength(0); + split.clear(); + } + super.visitElement(element); + } + }); + editor.getDocument().setText(sb.toString()); + return true; + } +} diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java index 75d676089ade..93e93177fbd7 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathReader.java @@ -168,8 +168,9 @@ public class EclipseClasspathReader { srcUrl = VfsUtil.pathToUrl(linked); eclipseModuleManager.registerEclipseLinkedSrcVarPath(srcUrl, path); rootModel.addContentEntry(srcUrl).addSourceFolder(srcUrl, isTestFolder); - } else { - getContentEntry().addSourceFolder(srcUrl, isTestFolder); + } + else { + myContentEntry.addSourceFolder(srcUrl, isTestFolder); } eclipseModuleManager.setExpectedModuleSourcePlace(rearrangeOrderEntryOfType(rootModel, ModuleSourceOrderEntry.class)); eclipseModuleManager.registerSrcPlace(srcUrl, idx); @@ -438,10 +439,6 @@ public class EclipseClasspathReader { return idx < 0 || idx == path.length() - 1 ? null : path.substring(idx + 1); } - private ContentEntry getContentEntry() { - return myContentEntry; - } - private static String getVariableRelatedPath(String var, String path) { return var == null ? null : ("$" + var + "$" + (path == null ? "" : ("/" + path))); } diff --git a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseClasspathTest.java b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseClasspathTest.java index ea2034fe7520..e2e67229c90f 100644 --- a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseClasspathTest.java +++ b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseClasspathTest.java @@ -39,6 +39,7 @@ import junit.framework.Assert; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; +import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.eclipse.config.EclipseClasspathStorageProvider; import org.jetbrains.idea.eclipse.conversion.ConversionException; import org.jetbrains.idea.eclipse.conversion.EclipseClasspathReader; @@ -74,7 +75,7 @@ public class EclipseClasspathTest extends IdeaTestCase { checkModule(path, setUpModule(path, project)); } - static Module setUpModule(final String path, final Project project) + static Module setUpModule(final String path, @NotNull final Project project) throws IOException, JDOMException, ConversionException, ConfigurationException { final File classpathFile = new File(path, EclipseXml.DOT_CLASSPATH_EXT); String fileText = FileUtil.loadFile(classpathFile).replaceAll("\\$ROOT\\$", project.getBaseDir().getPath()); diff --git a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java index d9490caf578d..82a261cdc3af 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java +++ b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java @@ -145,11 +145,11 @@ public class GitAnnotationProvider implements AnnotationProvider, VcsCacheableAn final VcsFileRevision revision, final List revisions, final VirtualFile file) throws VcsException { - GitSimpleHandler h = new GitSimpleHandler(myProject, GitUtil.getGitRoot(repositoryFilePath), GitCommand.ANNOTATE); + GitSimpleHandler h = new GitSimpleHandler(myProject, GitUtil.getGitRoot(repositoryFilePath), GitCommand.BLAME); h.setNoSSH(true); h.setStdoutSuppressed(true); h.setCharset(file.getCharset()); - h.addParameters("-p", "-l", "-t"); + h.addParameters("-p", "-l", "-t", "-w"); if (revision == null) { h.addParameters("HEAD"); } diff --git a/plugins/git4idea/src/git4idea/commands/GitCommand.java b/plugins/git4idea/src/git4idea/commands/GitCommand.java index 302caeccc76b..2528424c8d1a 100644 --- a/plugins/git4idea/src/git4idea/commands/GitCommand.java +++ b/plugins/git4idea/src/git4idea/commands/GitCommand.java @@ -35,7 +35,7 @@ import org.jetbrains.annotations.NotNull; public class GitCommand { public static final GitCommand ADD = write("add"); - public static final GitCommand ANNOTATE = read("annotate"); + public static final GitCommand BLAME = read("blame"); public static final GitCommand BRANCH = read("branch"); public static final GitCommand CHECKOUT = write("checkout"); public static final GitCommand COMMIT = write("commit"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 8e7de64218df..21fc4b593aaa 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -122,8 +122,8 @@ field.already.defined=Field ''{0}'' already defined import.what=Import ''{0}'' import.class=Import Class create.class.family.name=Create Class -create.class.text=Create Class ''{0}'' -create.interface.text=Create Interface ''{0}'' +create.class.text=Create Class {0} +create.interface.text=Create Interface {0} static.declaration.in.inner.class=Inner classes cannot have static declarations constructors.are.not.allowed.in.anonymous.class=Constructors are not allowed in anonymous class no.such.property=Property ''{0}'' does not exist @@ -311,3 +311,5 @@ type.argument.0.is.not.in.its.bound.should.extend.1=Type parameter ''{0}'' is no catch.statement.parameter.type.should.be.a.subclass.of.throwable=Catch statement parameter type should be a subclass of Throwable exception.0.has.already.been.caught=Exception ''{0}'' has already been caught unnecessary.type=Unnecessary exception ''{0}''. ''{1}'' is already declared +create.enum=Create Enum {0} +create.inner.class=Create Inner Class {0} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 1d0368b1bfff..1bcc53574892 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -1001,16 +1001,17 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } private static boolean checkDiamonds(GrCodeReferenceElement refElement, AnnotationHolder holder) { - final GroovyConfigUtils configUtils = GroovyConfigUtils.getInstance(); - if (configUtils.isVersionAtLeast(refElement, GroovyConfigUtils.GROOVY1_8)) return true; - GrTypeArgumentList typeArgumentList = refElement.getTypeArgumentList(); - if (typeArgumentList != null && typeArgumentList.isDiamond()) { + if (typeArgumentList == null) return true; + + if (!typeArgumentList.isDiamond()) return true; + + final GroovyConfigUtils configUtils = GroovyConfigUtils.getInstance(); + if (!configUtils.isVersionAtLeast(refElement, GroovyConfigUtils.GROOVY1_8)) { final String message = GroovyBundle.message("diamonds.are.not.allowed.in.groovy.0", configUtils.getSDKVersion(refElement)); holder.createErrorAnnotation(typeArgumentList, message); - return false; } - return true; + return false; } @Override @@ -1951,11 +1952,33 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { annotation.registerFix(CreateClassFix.createClassFromNewAction((GrNewExpression)parent)); } else { - annotation.registerFix(CreateClassFix.createClassFixAction(refElement)); + if (shouldBeInterface(refElement)) { + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.INTERFACE)); + } + else if (shouldBeClass(refElement)) { + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.CLASS)); + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.ENUM)); + } + else { + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.CLASS)); + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.INTERFACE)); + annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.ENUM)); + } } } } + private static boolean shouldBeInterface(GrReferenceElement myRefElement) { + PsiElement parent = myRefElement.getParent(); + return parent instanceof GrImplementsClause || parent instanceof GrExtendsClause && parent.getParent() instanceof GrInterfaceDefinition; + } + + private static boolean shouldBeClass(GrReferenceElement myRefElement) { + PsiElement parent = myRefElement.getParent(); + return parent instanceof GrExtendsClause && !(parent.getParent() instanceof GrInterfaceDefinition); + } + + private static void highlightMember(AnnotationHolder holder, GrMember member) { if (member instanceof GrField) { GrField field = (GrField)member; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java index 5d6d8c86d687..07822de94efb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassActionBase.java @@ -34,26 +34,35 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrInterfaceDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; /** * @author ilyas */ public abstract class CreateClassActionBase implements IntentionAction { + private Type myType; + protected final GrReferenceElement myRefElement; private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.annotator.intentions.CreateClassActionBase"); - public CreateClassActionBase(GrReferenceElement refElement) { + public CreateClassActionBase(Type type, GrReferenceElement refElement) { + myType = type; myRefElement = refElement; } @NotNull public String getText() { String referenceName = myRefElement.getReferenceName(); - return shouldCreateInterface() ? GroovyBundle.message("create.interface.text", referenceName) : GroovyBundle.message("create.class.text", referenceName); + switch (getType()) { + case ENUM: + return GroovyBundle.message("create.enum", referenceName); + case CLASS: + return GroovyBundle.message("create.class.text", referenceName); + case INTERFACE: + return GroovyBundle.message("create.interface.text", referenceName); + default: + return ""; + } } @NotNull @@ -69,17 +78,17 @@ public abstract class CreateClassActionBase implements IntentionAction { return true; } - protected boolean shouldCreateInterface() { - PsiElement parent = myRefElement.getParent(); - return parent instanceof GrImplementsClause || parent instanceof GrExtendsClause && parent.getParent() instanceof GrInterfaceDefinition; + + protected Type getType() { + return myType; } @Nullable - public static GrTypeDefinition createClassByType(@NotNull final PsiDirectory directory, - @NotNull final String name, - @NotNull final PsiManager manager, - @Nullable final PsiElement contextElement, - @NotNull final String templateName) { + public static GrTypeDefinition createClassByType(@NotNull final PsiDirectory directory, + @NotNull final String name, + @NotNull final PsiManager manager, + @Nullable final PsiElement contextElement, + @NotNull final String templateName) { AccessToken accessToken = WriteAction.start(); try { @@ -130,8 +139,13 @@ public abstract class CreateClassActionBase implements IntentionAction { if (virtualFile != null) { OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile, textOffset); return FileEditorManager.getInstance(project).openTextEditor(descriptor, true); - } else { + } + else { return null; } } + + public static enum Type { + ENUM, CLASS, INTERFACE + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassFix.java index dcc285a8e05b..c7a44098fe4b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateClassFix.java @@ -27,7 +27,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.actions.NewGroovyClassAction; import org.jetbrains.plugins.groovy.intentions.base.IntentionUtils; import org.jetbrains.plugins.groovy.lang.editor.template.expressions.ChooseTypeExpression; @@ -50,7 +49,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; public abstract class CreateClassFix { public static IntentionAction createClassFromNewAction(final GrNewExpression expression) { - return new CreateClassActionBase(expression.getReferenceElement()) { + return new CreateClassActionBase(CreateClassActionBase.Type.CLASS, expression.getReferenceElement()) { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { if (!(file instanceof GroovyFileBase)) return; @@ -60,7 +59,7 @@ public abstract class CreateClassFix { final String name = myRefElement.getReferenceName(); assert name != null; final Module module = ModuleUtil.findModuleForPsiElement(file); - PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module); + PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module, getText()); if (targetDirectory == null) return; GrTypeDefinition targetClass = createClassByType(targetDirectory, name, manager, myRefElement, NewGroovyClassAction.GROOVY_CLASS); @@ -96,8 +95,8 @@ public abstract class CreateClassFix { }; } - public static IntentionAction createClassFixAction(final GrReferenceElement refElement) { - return new CreateClassActionBase(refElement) { + public static IntentionAction createClassFixAction(final GrReferenceElement refElement, CreateClassActionBase.Type type) { + return new CreateClassActionBase(type, refElement) { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { if (!(file instanceof GroovyFileBase)) return; @@ -106,10 +105,22 @@ public abstract class CreateClassFix { final PsiManager manager = PsiManager.getInstance(project); final String name = myRefElement.getReferenceName(); final Module module = ModuleUtil.findModuleForPsiElement(file); - PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module); + PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module, getText()); if (targetDirectory == null) return; - String templateName = shouldCreateInterface() ? NewGroovyClassAction.GROOVY_INTERFACE : NewGroovyClassAction.GROOVY_CLASS; + + String templateName = null; + switch (getType()) { + case ENUM: + templateName = NewGroovyClassAction.GROOVY_ENUM; + break; + case CLASS: + templateName = NewGroovyClassAction.GROOVY_CLASS; + break; + case INTERFACE: + templateName = NewGroovyClassAction.GROOVY_INTERFACE; + break; + } assert name != null; PsiClass targetClass = createClassByType(targetDirectory, name, manager, myRefElement, templateName); if (targetClass != null) { @@ -122,8 +133,7 @@ public abstract class CreateClassFix { } @Nullable - private static PsiDirectory getTargetDirectory(Project project, String qualifier, String name, Module module) { - String title = GroovyBundle.message("create.class.family.name"); + private static PsiDirectory getTargetDirectory(Project project, String qualifier, String name, Module module, String title) { GroovyCreateClassDialog dialog = new GroovyCreateClassDialog(project, title, name, qualifier, module); dialog.show(); if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java index 8d745b479c01..33d5876beb45 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateParameterFromUsageFix.java @@ -21,10 +21,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.refactoring.RefactoringBundle; @@ -141,8 +138,13 @@ public class CreateParameterFromUsageFix implements IntentionAction, MethodOrClo final String name = ref.getName(); final Set types = GroovyExpectedTypesProvider.getDefaultExpectedTypes(ref); - PsiType _type = types.iterator().next(); - final PsiType type = TypesUtil.unboxPrimitiveTypeWrapper(_type); + final PsiType type; + if (types.isEmpty()) { + type = PsiType.getJavaLangObject(PsiManager.getInstance(project), ref.getResolveScope()); + } + else { + type = TypesUtil.unboxPrimitiveTypeWrapper(types.iterator().next()); + } if (method instanceof GrMethod) { new GrChangeSignatureDialog(project, (GrMethod)method) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java index 7caa247467ce..781e1963eac4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java @@ -67,7 +67,7 @@ public class GroovyCreateClassDialog extends DialogWrapper { setModal(true); setTitle(title); - myInformationLabel.setText(GroovyInspectionBundle.message("dialog.create.class.label.0", targetClassName)); + myInformationLabel.setText(title); myPackageTextField.setText(targetPackageName != null ? targetPackageName : ""); init(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyLibraryDescription.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyLibraryDescription.java index b06652ad81b0..529479e02c29 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyLibraryDescription.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyLibraryDescription.java @@ -23,6 +23,7 @@ import com.intellij.openapi.roots.libraries.NewLibraryConfiguration; import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription; import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor; import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -121,6 +122,7 @@ public class GroovyLibraryDescription extends CustomLibraryDescription { final String path = dir.getPath(); final String sdkVersion = provider.getSDKVersion(path); if (AbstractConfigUtils.UNDEFINED_VERSION.equals(sdkVersion)) { + Messages.showErrorDialog(parentComponent, "Looks like " + myFrameworkName + " distribution in specified path is broken. Cannot determinate version.", "Failed to create library"); return null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java index 3e604a744937..3f4182719b1d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java @@ -61,7 +61,8 @@ public class GDKSuperMethodSearcher implements QueryExecutor SPREAD_STATE = Key.create("Spread state"); + + private final PsiType containerType; + @Nullable private final SpreadState innerState; + + public SpreadState(PsiType type, @Nullable SpreadState state) { + containerType = type; + innerState = state; + } + + public PsiType getContainerType() { + return containerType; + } + + @Nullable + public SpreadState getInnerState() { + return innerState; + } + + public static SpreadState create(PsiType type, @Nullable SpreadState state) { + return new SpreadState(type, state); + } + + public static PsiType apply(PsiType item, @Nullable SpreadState state, Project project) { + if (state == null) return item; + return apply(TypesUtil.createSimilarCollection(state.getContainerType(), project, item), state.getInnerState(), project); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/GrMemberOwner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/GrMemberOwner.java index f2256fc8fa5f..dd269d9f46c2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/GrMemberOwner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/GrMemberOwner.java @@ -19,12 +19,13 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMembersDeclaration; /** * @author ilyas */ public interface GrMemberOwner extends PsiClass { - T addMemberDeclaration(T decl, PsiElement anchorBefore) throws IncorrectOperationException ; + T addMemberDeclaration(T decl, @Nullable PsiElement anchorBefore) throws IncorrectOperationException ; } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index 50b5bac05291..e33b7c2684c0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -36,6 +36,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlo import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseLabel; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; @@ -391,6 +393,35 @@ public class GroovyExpectedTypesProvider { } } + @Override + public void visitCaseLabel(GrCaseLabel caseLabel) { + final PsiElement parent = caseLabel.getParent().getParent(); + assert parent instanceof GrSwitchStatement; + final GrExpression condition = ((GrSwitchStatement)parent).getCondition(); + if (condition == null) return; + + final PsiType type = condition.getType(); + if (type == null) return; + + myResult = new TypeConstraint[]{SubtypeConstraint.create(type)}; + } + + @Override + public void visitSwitchStatement(GrSwitchStatement switchStatement) { + final GrCaseSection[] sections = switchStatement.getCaseSections(); + List types = new ArrayList(sections.length); + for (GrCaseSection section : sections) { + final GrExpression value = section.getCaseLabel().getValue(); + final PsiType type = value != null ? value.getType() : null; + if (type != null) types.add(type); + } + + final PsiType upperBoundNullable = TypesUtil.getLeastUpperBoundNullable(types, switchStatement.getManager()); + if (upperBoundNullable == null) return; + + myResult = new TypeConstraint[]{SubtypeConstraint.create(upperBoundNullable)}; + } + public TypeConstraint[] getResult() { return myResult; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java new file mode 100644 index 000000000000..99b1556901de --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl; + +import com.intellij.openapi.project.Project; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +/** + * @author Max Medvedev + */ +public class GrSpreadType extends GrLiteralClassType { + + private PsiType myType; + + public GrSpreadType(PsiType original, PsiType containerType, GlobalSearchScope scope) { + this(original, containerType, LanguageLevel.JDK_1_5, scope, JavaPsiFacade.getInstance(scope.getProject())); + } + + public GrSpreadType(PsiType original, PsiType containerType, LanguageLevel languageLevel, GlobalSearchScope scope, JavaPsiFacade facade) { + super(languageLevel, scope, facade); + + final Project project = facade.getProject(); + myType = TypesUtil.createSimilarCollection(containerType, project, original); + } + + @NotNull + @Override + protected String getJavaClassName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public String getClassName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public PsiType[] getParameters() { + return new PsiType[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getInternalCanonicalText() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean isValid() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index eb22d3caf49b..f9a4f0e8e667 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -396,6 +396,12 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { return createTypeElement(typeText); } + @NotNull + @Override + public PsiClassType createType(@NotNull PsiClass aClass) { + return JavaPsiFacade.getElementFactory(myProject).createType(aClass); + } + public GrParenthesizedExpression createParenthesizedExpr(GrExpression newExpr) { return ((GrParenthesizedExpression) getInstance(myProject).createExpressionFromText("(" + newExpr.getText() + ")")); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java index e8b06b9c8eee..0f4521128023 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java @@ -16,10 +16,12 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; /** * @author ven @@ -31,28 +33,30 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { private final PsiSubstitutor mySubstitutor; private final boolean myIsInvokedOnProperty; - private GroovyPsiElement myCurrentFileResolveContext; + private final GroovyPsiElement myCurrentFileResolveContext; + private final SpreadState mySpreadState; - public GroovyResolveResultImpl(PsiElement element, boolean isAccessible) { - this(element, null, PsiSubstitutor.EMPTY, isAccessible, true); + public GroovyResolveResultImpl(@NotNull PsiElement element, boolean isAccessible) { + this(element, null, null, PsiSubstitutor.EMPTY, isAccessible, true, false); } - public GroovyResolveResultImpl(PsiElement element, - @Nullable GroovyPsiElement context, - PsiSubstitutor substitutor, + public GroovyResolveResultImpl(@NotNull PsiElement element, + @Nullable GroovyPsiElement resolveContext, + @Nullable SpreadState spreadState, + @NotNull PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK) { - this(element, context, substitutor, isAccessible, staticsOK, false); + this(element, resolveContext, spreadState, substitutor, isAccessible, staticsOK, false); } public GroovyResolveResultImpl(PsiClassType.ClassResolveResult classResolveResult) { - this(classResolveResult.getElement(), null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), - classResolveResult.isStaticsScopeCorrect()); + this(classResolveResult.getElement(), null, null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), classResolveResult.isStaticsScopeCorrect(), false); } - public GroovyResolveResultImpl(PsiElement element, - GroovyPsiElement resolveContext, - PsiSubstitutor substitutor, + public GroovyResolveResultImpl(@NotNull PsiElement element, + @Nullable GroovyPsiElement resolveContext, + @Nullable SpreadState spreadState, + @NotNull PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK, boolean isInvokedOnProperty) { @@ -62,8 +66,10 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { mySubstitutor = substitutor; myIsStaticsOK = staticsOK; myIsInvokedOnProperty = isInvokedOnProperty; + mySpreadState = spreadState; } + @NotNull public PsiSubstitutor getSubstitutor() { return mySubstitutor; } @@ -108,6 +114,7 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { return result; } + @Nullable public GroovyPsiElement getCurrentFileResolveContext() { return myCurrentFileResolveContext; } @@ -116,6 +123,11 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { return myIsInvokedOnProperty; } + @Override + public SpreadState getSpreadState() { + return mySpreadState; + } + @Override public String toString() { return "GroovyResolveResultImpl{" + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java index b1eb3ea33932..e6c630bef390 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java @@ -95,7 +95,7 @@ public class GrConstructorInvocationImpl extends GrCallImpl implements GrConstru } public GroovyResolveResult[] multiResolveClass() { - return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, PsiSubstitutor.EMPTY, true, true)}; + return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, null, PsiSubstitutor.EMPTY, true, true)}; } public PsiMethod resolveMethod() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 080bc3d9e4cc..75e809c5b795 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -117,7 +118,7 @@ public class CompleteReferenceExpression { getVariantsFromQualifierForSpreadOperator(refExpr, processor, qualifier); } } - ResolveUtil.processCategoryMembers(refExpr, processor); + ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial()); } private static void getVariantsFromQualifierForSpreadOperator(GrReferenceExpression refExpr, @@ -206,8 +207,8 @@ public class CompleteReferenceExpression { final GrPropertyForCompletion field = new GrPropertyForCompletion(method, name, type); if (resolveResult != null) { - return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSubstitutor(), - resolveResult.isAccessible(), resolveResult.isStaticsOK()); + return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSpreadState(), + resolveResult.getSubstitutor(), resolveResult.isAccessible(), resolveResult.isStaticsOK(), false); } else { return new GroovyResolveResultImpl(field, true); @@ -377,12 +378,13 @@ public class CompleteReferenceExpression { boolean isAccessible = isAccessible(namedElement); final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT); + final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE); boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, myParameters.getInvocationCount() <= 1); PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; - consume(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK)); + consume(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK)); return true; } @@ -407,7 +409,7 @@ public class CompleteReferenceExpression { element = ((GrReflectedMethod)element).getBaseMethod(); if (!myProcessedMethodWithOptionalParams.add((GrMethod)element)) return; - result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), + result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), result.getSpreadState(), result.getSubstitutor(), result.isAccessible(), result.isStaticsOK(), result.isInvokedOnProperty()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 8cdc0970c303..6c54eeebb8d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -64,7 +65,8 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mAT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mMEMBER_POINTER; /** * @author ilyas @@ -121,7 +123,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl accessorResults = new ArrayList(); for (String accessorName : accessorNames) { - AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments()); + AccessorResolverProcessor accessorResolver = + new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments()); GrReferenceResolveUtil.resolveImpl(accessorResolver, this); final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); @@ -198,7 +202,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl>() { - @Override - public Result> compute() { - return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT); - } - }); + return CachedValuesManager.getManager(getProject()) + .getCachedValue(this, new CachedValueProvider>() { + @Override + public Result> compute() { + return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT); + } + }); } private Pair doResolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) { @@ -329,7 +334,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl() { @Override public Result compute() { - GroovyResolveResult[] value = RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable() { - @Override - public GroovyResolveResult[] compute() { - return doPolyResolve(false, false); - } - }); + GroovyResolveResult[] value = + RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable() { + @Override + public GroovyResolveResult[] compute() { + return doPolyResolve(false, false); + } + }); if (value == null) { value = GroovyResolveResult.EMPTY_ARRAY; } @@ -459,8 +468,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl 1) { PsiParameter last = parameters[parameters.length - 1]; - return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), this); + return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), candidate.getSpreadState(), this); } } return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java index be8c8d08977b..afd5148ac5c0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java @@ -102,8 +102,7 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { } public GroovyResolveResult[] multiResolveClass() { - final PsiClass psiClass = getContainingClass(); - GroovyResolveResult result = new GroovyResolveResultImpl(psiClass, this, PsiSubstitutor.EMPTY, true, true); + GroovyResolveResult result = new GroovyResolveResultImpl(getContainingClass(), this, null, PsiSubstitutor.EMPTY, true, true); return new GroovyResolveResult[]{result}; } @@ -135,7 +134,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { public GrExpression[] getExpressionArguments() { final GrArgumentList argumentList = getArgumentList(); return argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments(); - } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 239e24f42bc7..0aed67b8c24e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -376,7 +376,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImplp ''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING,$JAVA_LANG_STRING>") } + void testSpread1() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +[new A()].string +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>") + } + + void testSpread2() { + + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +class Cat { + static getFoo(String b) {2} +} +use(Cat) { + [new A()].string.foo +} +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>") + } + + void testSpread3() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +[[new A()]].string +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>>") + } + + void testSpread4() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +class Cat { + static getFoo(String b) {2} +} + +use(Cat){ + [[new A()]].string.foo +} +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>>") + } private void doTest(String text, String type) { def file = myFixture.configureByText('_.groovy', text) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java index 4edea976f712..1574ebfb85c7 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceVariable/IntroduceVariableTest.java @@ -71,6 +71,7 @@ public class IntroduceVariableTest extends LightCodeInsightFixtureTestCase { public void testLoop7() throws Throwable { doTest(); } public void testLoop8() throws Throwable { doTest(); } public void testInCase() {doTest();} + public void testCaseLabel() {doTest();} public void testDuplicatesInsideIf() throws Throwable { doTest(); } public void testFromGString() throws Throwable { doTest(); } diff --git a/plugins/groovy/testdata/groovy/refactoring/introduceVariable/caseLabel.test b/plugins/groovy/testdata/groovy/refactoring/introduceVariable/caseLabel.test new file mode 100644 index 000000000000..0bc8dc3d3094 --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/introduceVariable/caseLabel.test @@ -0,0 +1,14 @@ +def test(int p) { + switch (p) { + case 1: println "111" + case xxx: println "xxx" + } +} +----- +def test(int p) { + def preved = 1 + switch (p) { + case preved: println "111" + case xxx: println "xxx" + } +} \ No newline at end of file diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/state/ProjectDictionarySplitter.java b/plugins/spellchecker/src/com/intellij/spellchecker/state/ProjectDictionarySplitter.java index dd2a5ff8d724..247ae439c808 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/state/ProjectDictionarySplitter.java +++ b/plugins/spellchecker/src/com/intellij/spellchecker/state/ProjectDictionarySplitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import com.intellij.openapi.components.StateSplitter; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.spellchecker.state.DictionaryState; import com.intellij.util.text.UniqueNameGenerator; import org.jdom.Element; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/TextEditor.java similarity index 91% rename from plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java rename to plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/TextEditor.java index 68435e5609ee..e226de011224 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/TextEditor.java @@ -27,10 +27,10 @@ import java.awt.event.ActionListener; /** * @author Alexander Lobas */ -public abstract class AbstractTextFieldEditor extends PropertyEditor { +public class TextEditor extends PropertyEditor { protected final JTextField myTextField = new JTextField(); - protected AbstractTextFieldEditor() { + public TextEditor() { myTextField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -47,6 +47,11 @@ public abstract class AbstractTextFieldEditor extends PropertyEditor { return myTextField; } + @Override + public Object getValue() throws Exception { + return myTextField.getText(); + } + protected void setEditorValue(@Nullable RadComponent component, Object value) { myTextField.setText(value == null ? "" : value.toString()); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java index c72f6ac58eb8..5b7dedcecae3 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java @@ -22,6 +22,7 @@ import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.intellij.lang.xpath.xslt.XsltSupport; +import org.jetbrains.annotations.NotNull; /* * Created by IntelliJ IDEA. @@ -30,7 +31,7 @@ import org.intellij.lang.xpath.xslt.XsltSupport; */ public class XsltChangeLocalityDetector implements ChangeLocalityDetector { @Override - public PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { try { if (changedElement instanceof XmlToken && changedElement.getNode().getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE_TOKEN) { final PsiElement grandParent = changedElement.getParent().getParent(); diff --git a/resources-en/src/inspectionDescriptions/ParameterCanBeLocal.html b/resources-en/src/inspectionDescriptions/ParameterCanBeLocal.html new file mode 100644 index 000000000000..81a3e513e6b6 --- /dev/null +++ b/resources-en/src/inspectionDescriptions/ParameterCanBeLocal.html @@ -0,0 +1,9 @@ + + + + This inspection searches for redundant method parameters that can be replaced with local variables. + If all local usages of a parameter are preceded by assignments to that parameter, the + parameter can be removed and its usages replaced with local variables. + + + diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index cb3175edc39c..30f80d8c791c 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -459,6 +459,9 @@ + @@ -535,6 +538,7 @@ groupName="Probable bugs" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.magicConstant.MagicConstantInspection" /> + com.intellij.codeInsight.intention.impl.SplitIfAction Control Flow @@ -969,6 +973,7 @@ + diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java index 2fd21d165ffe..8d98f7fe61f9 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java @@ -51,7 +51,6 @@ import com.intellij.psi.xml.XmlToken; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ObjectUtils; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlExtension; import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; @@ -102,6 +101,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi myToken = token == null ? null : PsiAnchor.create(token); } + @Override @NotNull public String getText() { final String alias = StringUtil.capitalize(getXmlExtension().getNamespaceAlias(getFile())); @@ -112,16 +112,19 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi return XmlExtension.getExtension(getFile()); } + @Override @NotNull public String getName() { return getFamilyName(); } + @Override @NotNull public String getFamilyName() { return getText(); } + @Override public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { final PsiFile containingFile = descriptor.getPsiElement().getContainingFile(); Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); @@ -133,15 +136,18 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi } } + @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { PsiElement element = myElement.retrieve(); return element != null && element.isValid(); } + @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; - final PsiElement element = ObjectUtils.assertNotNull(myElement.retrieve()); + final PsiElement element = myElement.retrieve(); + if (element == null) return; final Set set = getXmlExtension().guessUnboundNamespaces(element, getFile()); final String[] namespaces = ArrayUtil.toStringArray(set); Arrays.sort(namespaces); @@ -150,6 +156,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi namespaces, project, new StringToAttributeProcessor() { + @Override public void doSomethingWithGivenStringToProduceXmlAttributeNowPlease(@NotNull final String namespace) throws IncorrectOperationException { String prefix = myNamespacePrefix; if (StringUtil.isEmpty(prefix)) { @@ -173,8 +180,9 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi final RangeMarker marker = editor.getDocument().createRangeMarker(offset, offset); final XmlExtension extension = XmlExtension.getExtension(file); extension.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(namespace), prefix, new XmlExtension.Runner() { + @Override public void run(final String param) throws IncorrectOperationException { - if (namespace.length() > 0) { + if (!namespace.isEmpty()) { editor.getCaretModel().moveToOffset(marker.getStartOffset()); } } @@ -189,18 +197,21 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi return XmlErrorMessages.message("select.namespace.title", StringUtil.capitalize(getXmlExtension().getNamespaceAlias(getFile()))); } + @Override public boolean startInWriteAction() { return true; } + @Override public boolean showHint(final Editor editor) { if (myToken == null) return false; XmlToken token = (XmlToken)myToken.retrieve(); if (token == null) return false; - if (!XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS || myNamespacePrefix.length() == 0) { + if (!XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS || myNamespacePrefix.isEmpty()) { return false; } - PsiElement element = ObjectUtils.assertNotNull(myElement.retrieve()); + final PsiElement element = myElement.retrieve(); + if (element == null) return false; final Set namespaces = getXmlExtension().guessUnboundNamespaces(element, getFile()); if (!namespaces.isEmpty()) { final String message = ShowAutoImportPass.getMessage(namespaces.size() > 1, namespaces.iterator().next()); @@ -224,13 +235,14 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi } private static boolean checkIfGivenXmlHasTheseWords(final String name, final XmlFile tldFileByUri) { - if (name == null || name.length() == 0) return true; + if (name == null || name.isEmpty()) return true; final List list = StringUtil.getWordsIn(name); final String[] words = ArrayUtil.toStringArray(list); final boolean[] wordsFound = new boolean[words.length]; final int[] wordsFoundCount = new int[1]; IdTableBuilding.ScanWordProcessor wordProcessor = new IdTableBuilding.ScanWordProcessor() { + @Override public void run(final CharSequence chars, @Nullable char[] charsArray, int start, int end) { if (wordsFoundCount[0] == words.length) return; final int foundWordLen = end - start; @@ -263,7 +275,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi } - public static void runActionOverSeveralAttributeValuesAfterLettingUserSelectTheNeededOne(final @NotNull String[] namespacesToChooseFrom, + public static void runActionOverSeveralAttributeValuesAfterLettingUserSelectTheNeededOne(@NotNull final String[] namespacesToChooseFrom, final Project project, final StringToAttributeProcessor onSelection, String title, final IntentionAction requestor, @@ -273,6 +285,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi final JList list = new JBList(namespacesToChooseFrom); list.setCellRenderer(XmlNSRenderer.INSTANCE); Runnable runnable = new Runnable() { + @Override public void run() { final int index = list.getSelectedIndex(); if (index < 0) return; @@ -281,9 +294,11 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi CommandProcessor.getInstance().executeCommand( project, new Runnable() { + @Override public void run() { ApplicationManager.getApplication().runWriteAction( new Runnable() { + @Override public void run() { try { onSelection.doSomethingWithGivenStringToProduceXmlAttributeNowPlease(namespacesToChooseFrom[index]); @@ -321,6 +336,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi else { ProgressManager.getInstance().runProcessWithProgressSynchronously( new Runnable() { + @Override public void run() { processExternalUrisImpl(metaHandler, file, processor); } @@ -345,6 +361,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi myName = name; } + @Override public boolean isAcceptableMetaData(final PsiMetaData metaData, final String url) { if (metaData instanceof XmlNSDescriptorImpl) { final XmlNSDescriptorImpl nsDescriptor = (XmlNSDescriptorImpl)metaData; @@ -355,6 +372,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi return false; } + @Override public String searchFor() { return myName; } diff --git a/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java new file mode 100644 index 000000000000..fb65aa55965d --- /dev/null +++ b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java @@ -0,0 +1,36 @@ +/* + * 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.xml; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.DefaultXmlSuppressionProvider; +import com.intellij.lang.xml.XMLLanguage; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +public class XmlChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + // rehighlight everything when inspection suppress comment changed + if (changedElement.getLanguage() instanceof XMLLanguage + && changedElement instanceof PsiComment + && changedElement.getText().contains(DefaultXmlSuppressionProvider.SUPPRESS_MARK)) { + return changedElement.getContainingFile(); + } + return null; + } +} diff --git a/xml/impl/src/com/intellij/xml/actions/ValidateXmlActionHandler.java b/xml/impl/src/com/intellij/xml/actions/ValidateXmlActionHandler.java index 2275976cd61a..aa7a8ae8bbd6 100644 --- a/xml/impl/src/com/intellij/xml/actions/ValidateXmlActionHandler.java +++ b/xml/impl/src/com/intellij/xml/actions/ValidateXmlActionHandler.java @@ -548,7 +548,7 @@ public class ValidateXmlActionHandler { final PsiFile psifile = PsiManager.getInstance(myProject).findFile(file); if (psifile != null && psifile.isValid()) { - timestamp += psifile.getModificationStamp(); + timestamp += psifile.getViewProvider().getModificationStamp(); } else { break; } diff --git a/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java b/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java index 8291ac3d4c9a..77ec93a89a50 100644 --- a/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java +++ b/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java @@ -36,16 +36,19 @@ import org.jetbrains.annotations.NotNull; */ public class XmlSplitTagAction implements IntentionAction { + @Override @NotNull public String getText() { return XmlBundle.message("xml.split.tag.intention.action"); } + @Override @NotNull public String getFamilyName() { return XmlBundle.message("xml.split.tag.intention.action"); } + @Override public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { if (file instanceof XmlFile) { if (editor != null) { @@ -75,6 +78,7 @@ public class XmlSplitTagAction implements IntentionAction { return "html".equals(name) || "body".equals(name) || "title".equals(name); } + @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; @@ -165,6 +169,7 @@ public class XmlSplitTagAction implements IntentionAction { return sb.toString(); } + @Override public boolean startInWriteAction() { return true; } diff --git a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java index f1ce3969dfc2..6aa1a22ad909 100644 --- a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java +++ b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java @@ -37,16 +37,20 @@ import org.jetbrains.annotations.Nullable; */ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { + public static final String SUPPRESS_MARK = "suppress"; + @Override public boolean isProviderAvailable(PsiFile file) { return true; } + @Override public boolean isSuppressedFor(PsiElement element, String inspectionId) { final XmlTag tag = element instanceof XmlFile ? ((XmlFile)element).getRootTag() : PsiTreeUtil.getContextOfType(element, XmlTag.class, false); return tag != null && findSuppression(tag, inspectionId, element) != null; } + @Override public void suppressForFile(PsiElement element, String inspectionId) { final PsiFile file = element.getContainingFile(); final XmlDocument document = ((XmlFile)file).getDocument(); @@ -55,6 +59,7 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { suppress(file, findFileSuppression(anchor, null, element), inspectionId, anchor.getTextRange().getStartOffset()); } + @Override public void suppressForTag(PsiElement element, String inspectionId) { final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); assert tag != null; @@ -140,7 +145,9 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { @NonNls protected String getPrefix() { - return "