diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/FullValueEvaluatorProvider.java b/java/debugger/impl/src/com/intellij/debugger/engine/FullValueEvaluatorProvider.java index 3d03d68750db..1d3f7e079fee 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/FullValueEvaluatorProvider.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/FullValueEvaluatorProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,11 +18,12 @@ package com.intellij.debugger.engine; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.xdebugger.frame.XFullValueEvaluator; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** - * Created by Egor on 04.10.2014. + * @author egor */ public interface FullValueEvaluatorProvider { - @NotNull XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext, ValueDescriptorImpl valueDescriptor); + @Nullable + XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext, ValueDescriptorImpl valueDescriptor); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index b58e35e2ab78..cd1aab494cee 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -146,7 +146,11 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV presentation = new JavaValuePresentation(value, myValueDescriptor.getIdLabel(), exception != null ? exception.getMessage() : null, myValueDescriptor); if (myValueDescriptor.getLastRenderer() instanceof FullValueEvaluatorProvider) { - node.setFullValueEvaluator(((FullValueEvaluatorProvider)myValueDescriptor.getLastRenderer()).getFullValueEvaluator(myEvaluationContext, myValueDescriptor)); + XFullValueEvaluator evaluator = ((FullValueEvaluatorProvider)myValueDescriptor.getLastRenderer()) + .getFullValueEvaluator(myEvaluationContext, myValueDescriptor); + if (evaluator != null) { + node.setFullValueEvaluator(evaluator); + } } else if (value.length() > XValueNode.MAX_VALUE_LENGTH) { node.setFullValueEvaluator(new XFullValueEvaluator() { diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java index b5596ceb3559..420638ed0c5e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,7 +18,6 @@ package com.intellij.debugger.settings; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.CompoundReferenceRenderer; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.util.ui.ColorIcon; import com.sun.jdi.*; @@ -29,20 +28,11 @@ import java.awt.*; /** * Created by Egor on 04.10.2014. */ -class ColorObjectRenderer extends CompoundReferenceRenderer { - +class ColorObjectRenderer extends ToStringBasedRenderer { public ColorObjectRenderer(final NodeRendererSettings rendererSettings) { super(rendererSettings, "Color", null, null); setClassName("java.awt.Color"); - } - - public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws - EvaluateException { - String res = calcToStringLabel(descriptor, evaluationContext, listener); - if (res != null) { - return res; - } - return super.calcLabel(descriptor, evaluationContext, listener); + setEnabled(true); } public Icon calcValueIcon(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException { @@ -55,6 +45,7 @@ class ColorObjectRenderer extends CompoundReferenceRenderer { if (valueField != null) { final Value rgbValue = objRef.getValue(valueField); if (rgbValue instanceof IntegerValue) { + @SuppressWarnings("UseJBColor") final Color color = new Color(((IntegerValue)rgbValue).value(), true); return new ColorIcon(16, 12, color, true); } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java new file mode 100644 index 000000000000..d770da07ea1b --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2015 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.debugger.settings; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.DebuggerUtils; +import com.intellij.debugger.engine.FullValueEvaluatorProvider; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; +import com.intellij.xdebugger.frame.XFullValueEvaluator; +import com.sun.jdi.*; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author egor + */ +public class GraphicsObjectRenderer extends ToStringBasedRenderer implements FullValueEvaluatorProvider { + public GraphicsObjectRenderer(final NodeRendererSettings rendererSettings) { + super(rendererSettings, "Graphics", null, null); + setClassName("sun.java2d.SunGraphics2D"); + setEnabled(true); + } + + @Nullable + @Override + public XFullValueEvaluator getFullValueEvaluator(final EvaluationContextImpl evaluationContext, final ValueDescriptorImpl valueDescriptor) { + try { + ObjectReference value = (ObjectReference)valueDescriptor.getValue(); + Field surfaceField = ((ClassType)value.type()).fieldByName("surfaceData"); + if (surfaceField == null) return null; + ObjectReference surfaceDataValue = (ObjectReference)value.getValue(surfaceField); + final Field bufImgField = ((ClassType)surfaceDataValue.type()).fieldByName("bufImg"); + if (bufImgField == null) return null; + final Value bufImgValue = surfaceDataValue.getValue(bufImgField); + Type type = bufImgValue.type(); + if (!(type instanceof ReferenceType) || !DebuggerUtils.instanceOf(type, "java.awt.Image")) { + return null; + } + return new CustomPopupFullValueEvaluator(DebuggerBundle.message("message.node.show.image"), evaluationContext) { + @Override + protected JComponent createComponent() { + return ImageObjectRenderer.createIconViewer(ImageObjectRenderer.getIcon(myEvaluationContext, bufImgValue, + "imageToBytes")); + } + }; + } catch (Exception ignored) {} + return null; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java index f74ba0f7105e..21c1e187ae4d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,37 +15,28 @@ */ package com.intellij.debugger.settings; +import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.FullValueEvaluatorProvider; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.CompoundReferenceRenderer; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.icons.AllIcons; import com.intellij.xdebugger.frame.XFullValueEvaluator; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; /** * Created by Egor on 04.10.2014. */ -class IconObjectRenderer extends CompoundReferenceRenderer implements FullValueEvaluatorProvider { - +class IconObjectRenderer extends ToStringBasedRenderer implements FullValueEvaluatorProvider { public IconObjectRenderer(final NodeRendererSettings rendererSettings) { super(rendererSettings, "Icon", null, null); setClassName("javax.swing.Icon"); - } - - public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws - EvaluateException { - String res = calcToStringLabel(descriptor, evaluationContext, listener); - if (res != null) { - return res; - } - return super.calcLabel(descriptor, evaluationContext, listener); + setEnabled(true); } @Override @@ -55,10 +46,10 @@ class IconObjectRenderer extends CompoundReferenceRenderer implements FullValueE return ImageObjectRenderer.getIcon(evaluationContext, descriptor.getValue(), getterName); } - @NotNull + @Nullable @Override public XFullValueEvaluator getFullValueEvaluator(final EvaluationContextImpl evaluationContext, final ValueDescriptorImpl valueDescriptor) { - return new CustomPopupFullValueEvaluator(" (Show icon)", evaluationContext) { + return new CustomPopupFullValueEvaluator(DebuggerBundle.message("message.node.show.icon"), evaluationContext) { @Override protected JComponent createComponent() { return ImageObjectRenderer.createIconViewer(ImageObjectRenderer.getIcon(myEvaluationContext, valueDescriptor.getValue(), "iconToBytes")); diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java index 6372092dc2e9..1fadbf518b59 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,20 +15,17 @@ */ package com.intellij.debugger.settings; +import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.FullValueEvaluatorProvider; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; -import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.CompoundReferenceRenderer; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.rt.debugger.ImageSerializer; import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.sun.jdi.*; import org.intellij.images.editor.impl.ImageEditorManagerImpl; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -40,25 +37,17 @@ import java.util.List; /** * Created by Egor on 04.10.2014. */ -class ImageObjectRenderer extends CompoundReferenceRenderer implements FullValueEvaluatorProvider { +class ImageObjectRenderer extends ToStringBasedRenderer implements FullValueEvaluatorProvider { public ImageObjectRenderer(final NodeRendererSettings rendererSettings) { super(rendererSettings, "Image", null, null); setClassName("java.awt.Image"); + setEnabled(true); } - public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws - EvaluateException { - String res = calcToStringLabel(descriptor, evaluationContext, listener); - if (res != null) { - return res; - } - return super.calcLabel(descriptor, evaluationContext, listener); - } - - @NotNull + @Nullable @Override public XFullValueEvaluator getFullValueEvaluator(final EvaluationContextImpl evaluationContext, final ValueDescriptorImpl valueDescriptor) { - return new CustomPopupFullValueEvaluator(" (Show image)", evaluationContext) { + return new CustomPopupFullValueEvaluator(DebuggerBundle.message("message.node.show.image"), evaluationContext) { @Override protected JComponent createComponent() { return createIconViewer(getIcon(myEvaluationContext, valueDescriptor.getValue(), "imageToBytes")); @@ -66,7 +55,8 @@ class ImageObjectRenderer extends CompoundReferenceRenderer implements FullValue }; } - static JComponent createIconViewer(Icon icon) { + static JComponent createIconViewer(@Nullable Icon icon) { + if (icon == null) return new JLabel("null", JLabel.CENTER); final int w = icon.getIconWidth(); final int h = icon.getIconHeight(); final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment() diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java index 32505cc41831..5874f8b33b86 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java @@ -78,9 +78,6 @@ public class NodeRendererSettings implements PersistentStateComponent { private final ClassRenderer myClassRenderer = new ClassRenderer(); private final HexRenderer myHexRenderer = new HexRenderer(); private final ToStringRenderer myToStringRenderer = new ToStringRenderer(); - private final CompoundReferenceRenderer myColorRenderer; - private final CompoundReferenceRenderer myImageRenderer; - private final CompoundReferenceRenderer myIconRenderer; // alternate collections private final NodeRenderer[] myAlternateCollectionRenderers = new NodeRenderer[]{ createCompoundReferenceRenderer( @@ -109,16 +106,10 @@ public class NodeRendererSettings implements PersistentStateComponent { @NonNls private static final String CUSTOM_RENDERERS_TAG_NAME = "CustomRenderers"; public NodeRendererSettings() { - myColorRenderer = new ColorObjectRenderer(this); - myImageRenderer = new ImageObjectRenderer(this); - myIconRenderer = new IconObjectRenderer(this); // default configuration myHexRenderer.setEnabled(false); myToStringRenderer.setEnabled(true); setAlternateCollectionViewsEnabled(true); - myColorRenderer.setEnabled(true); - myImageRenderer.setEnabled(true); - myIconRenderer.setEnabled(true); } public static NodeRendererSettings getInstance() { @@ -288,9 +279,6 @@ public class NodeRendererSettings implements PersistentStateComponent { } }); Collections.addAll(allRenderers, myAlternateCollectionRenderers); - allRenderers.add(myColorRenderer); - allRenderers.add(myImageRenderer); - allRenderers.add(myIconRenderer); allRenderers.add(myToStringRenderer); allRenderers.add(myArrayRenderer); allRenderers.add(myClassRenderer); diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java b/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java new file mode 100644 index 000000000000..9db4db739fb9 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2015 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.debugger.settings; + +import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.ui.tree.ValueDescriptor; +import com.intellij.debugger.ui.tree.render.*; + +/** + * @author egor + */ +public abstract class ToStringBasedRenderer extends CompoundReferenceRenderer { + public ToStringBasedRenderer(NodeRendererSettings rendererSettings, + String name, + ValueLabelRenderer labelRenderer, + ChildrenRenderer childrenRenderer) { + super(rendererSettings, name, labelRenderer, childrenRenderer); + } + + public String calcLabel(ValueDescriptor descriptor, + EvaluationContext evaluationContext, + DescriptorLabelListener listener) throws EvaluateException { + String res = calcToStringLabel(descriptor, evaluationContext, listener); + if (res != null) { + return res; + } + return super.calcLabel(descriptor, evaluationContext, listener); + } + + protected String calcToStringLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) + throws EvaluateException { + final ToStringRenderer toStringRenderer = myRendererSettings.getToStringRenderer(); + if (toStringRenderer.isEnabled() && DebuggerManagerEx.getInstanceEx(evaluationContext.getProject()).getContext().isEvaluationPossible()) { + return toStringRenderer.calcLabel(descriptor, evaluationContext, listener); + } + return null; + } + +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java index 9522e7150f4b..4cb8a56021f2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/CompoundReferenceRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,12 +15,8 @@ */ package com.intellij.debugger.ui.tree.render; -import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.DebuggerUtils; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.settings.NodeRendererSettings; -import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.CommonClassNames; import com.sun.jdi.ReferenceType; @@ -110,15 +106,6 @@ public class CompoundReferenceRenderer extends CompoundNodeRenderer{ } } - protected String calcToStringLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) - throws EvaluateException { - final ToStringRenderer toStringRenderer = myRendererSettings.getToStringRenderer(); - if (toStringRenderer.isEnabled() && DebuggerManagerEx.getInstanceEx(evaluationContext.getProject()).getContext().isEvaluationPossible()) { - return toStringRenderer.calcLabel(descriptor, evaluationContext, listener); - } - return null; - } - public @NotNull String getClassName() { return myProperties.getClassName(); } diff --git a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java index f2738ff51dcf..edd6516ce5c5 100644 --- a/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java +++ b/java/idea-ui/src/com/intellij/ide/impl/NewProjectUtil.java @@ -225,9 +225,8 @@ public class NewProjectUtil { if (version != null) { LanguageLevel maxLevel = version.getMaxLanguageLevel(); LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(ProjectManager.getInstance().getDefaultProject()); - Boolean aDefault = extension.isDefault(); LanguageLevelProjectExtension ext = LanguageLevelProjectExtension.getInstance(project); - if (aDefault != null && aDefault || maxLevel.compareTo(ext.getLanguageLevel()) < 0) { + if (extension.isDefault() || maxLevel.compareTo(ext.getLanguageLevel()) < 0) { ext.setLanguageLevel(maxLevel); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ContentEntriesEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ContentEntriesEditor.java index d4677c1f7a09..188a4f90ea4f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ContentEntriesEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ContentEntriesEditor.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; import javax.swing.*; import java.awt.*; @@ -52,6 +53,7 @@ public class ContentEntriesEditor extends JavaContentEntriesEditor { return getModel().getModuleExtension(LanguageLevelModuleExtensionImpl.class); } }; + myLanguageLevelConfigurable.addProjectDefault(LanguageLevelProjectExtension.getInstance(myProject).getLanguageLevel()); mainPanel.add(myLanguageLevelConfigurable.createComponent(), BorderLayout.NORTH); myLanguageLevelConfigurable.reset(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelCombo.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelCombo.java index 9716dbee0f6d..6c158a9e4ca0 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelCombo.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelCombo.java @@ -16,16 +16,18 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.core.JavaCoreBundle; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.JavaSdk; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ex.ProjectRootManagerEx; -import com.intellij.ui.ListCellRendererWrapper; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.roots.ex.ProjectRootManagerEx; import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.util.Pair; import com.intellij.pom.java.LanguageLevel; +import com.intellij.ui.ColoredListCellRendererWrapper; +import com.intellij.ui.SimpleTextAttributes; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -33,24 +35,30 @@ import javax.swing.*; /** * @author ven */ +@SuppressWarnings("unchecked") public class LanguageLevelCombo extends ComboBox { - public static final String USE_PROJECT_LANGUAGE_LEVEL = ProjectBundle.message("project.language.level.combo.item"); + /** Default from current SDK */ @Nullable private LanguageLevel myDefaultLevel; + private Pair myProjectDefault; public LanguageLevelCombo() { for (LanguageLevel level : LanguageLevel.values()) { addItem(level); } - setRenderer(new ListCellRendererWrapper() { + setRenderer(new ColoredListCellRendererWrapper() { @Override - public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean hasFocus) { + protected void doCustomize(JList list, Object value, int index, boolean selected, boolean hasFocus) { if (value instanceof LanguageLevel) { - setText(((LanguageLevel)value).getPresentableText()); + append(((LanguageLevel)value).getPresentableText()); } - else if (value instanceof String) { - setText((String)value); + else if (value instanceof Pair) { + Pair pair = (Pair)value; + append(pair.first); + if (pair.second != null) { + append(" (" + pair.second + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); + } } } }); @@ -69,20 +77,19 @@ public class LanguageLevelCombo extends ComboBox { myDefaultLevel = version.getMaxLanguageLevel(); } } - String item = null; + Pair item = null; if (myDefaultLevel != null) { - item = JavaCoreBundle.message("default.jdk.level.description", myDefaultLevel.getPresentableText()); + item = Pair.create(JavaCoreBundle.message("default.language.level.description"), myDefaultLevel.getPresentableText()); addItem(item); } else if (project.isDefault()) { - item = JavaCoreBundle.message("default.language.level.description"); + item = Pair.create(JavaCoreBundle.message("default.language.level.description"), null); addItem(item); myDefaultLevel = LanguageLevelProjectExtension.getInstance(project).getLanguageLevel(); } LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(project); - Boolean aDefault = extension.isDefault(); - if (item != null && aDefault != null && aDefault) { + if (item != null && extension.isDefault()) { setSelectedItem(item); } else { @@ -102,9 +109,11 @@ public class LanguageLevelCombo extends ComboBox { @Override public void setSelectedItem(Object anObject) { - if (anObject == null) { - anObject = USE_PROJECT_LANGUAGE_LEVEL; - } - super.setSelectedItem(anObject); + super.setSelectedItem(anObject == null ? myProjectDefault : anObject); + } + + void addProjectDefault(String projectLevel) { + myProjectDefault = Pair.create(ProjectBundle.message("project.language.level.combo.item"), projectLevel); + insertItemAt(myProjectDefault, 0); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelConfigurable.java index a22242f4093a..8199f714eab5 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LanguageLevelConfigurable.java @@ -21,6 +21,7 @@ import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl; import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -44,7 +45,6 @@ public abstract class LanguageLevelConfigurable implements UnnamedConfigurable { getLanguageLevelExtension().setLanguageLevel(languageLevel instanceof LanguageLevel ? (LanguageLevel)languageLevel : null); } }); - myLanguageLevelCombo.insertItemAt(LanguageLevelCombo.USE_PROJECT_LANGUAGE_LEVEL, 0); JLabel label = new JLabel(ProjectBundle.message("module.module.language.level")); label.setLabelFor(myLanguageLevelCombo); @@ -54,6 +54,7 @@ public abstract class LanguageLevelConfigurable implements UnnamedConfigurable { new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(6, 6, 12, 0), 0, 0)); } + @NotNull @Override public JComponent createComponent() { return myPanel; @@ -81,4 +82,8 @@ public abstract class LanguageLevelConfigurable implements UnnamedConfigurable { } public abstract LanguageLevelModuleExtensionImpl getLanguageLevelExtension(); + + public void addProjectDefault(LanguageLevel projectDefault) { + myLanguageLevelCombo.addProjectDefault(projectDefault.getPresentableText()); + } } diff --git a/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java b/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java index 2335a0e23a86..d9e5a703efef 100644 --- a/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java +++ b/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java @@ -22,6 +22,9 @@ package com.intellij.openapi.roots.impl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.roots.ProjectExtension; import com.intellij.openapi.util.InvalidDataException; @@ -30,6 +33,7 @@ import com.intellij.pom.java.LanguageLevel; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class LanguageLevelProjectExtensionImpl extends LanguageLevelProjectExtension { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.LanguageLevelProjectExtensionImpl"); @@ -76,7 +80,7 @@ import org.jetbrains.annotations.NotNull; private void writeExternal(final Element element) { element.setAttribute(LANGUAGE_LEVEL, myLanguageLevel.name()); - Boolean aBoolean = isDefault(); + Boolean aBoolean = getDefault(); if (aBoolean != null) { element.setAttribute(DEFAULT_ATTRIBUTE, Boolean.toString(aBoolean)); } @@ -116,21 +120,35 @@ import org.jetbrains.annotations.NotNull; LOG.warn("Calling deprecated LanguageLevelProjectExtensionImpl.reloadProjectOnLanguageLevelChange, while project reloading is not needed on language level changes"); } + private void projectSdkChanged(@Nullable Sdk sdk) { + if (isDefault() && sdk != null) { + JavaSdkVersion version = JavaSdk.getInstance().getVersion(sdk); + if (version != null) { + setLanguageLevel(version.getMaxLanguageLevel()); + } + } + } + public static class MyProjectExtension extends ProjectExtension { - private final Project myProject; + private final LanguageLevelProjectExtensionImpl myInstance; public MyProjectExtension(final Project project) { - myProject = project; + myInstance = ((LanguageLevelProjectExtensionImpl)getInstance(project)); } @Override public void readExternal(final Element element) throws InvalidDataException { - ((LanguageLevelProjectExtensionImpl)getInstance(myProject)).readExternal(element); + myInstance.readExternal(element); } @Override public void writeExternal(final Element element) throws WriteExternalException { - ((LanguageLevelProjectExtensionImpl)getInstance(myProject)).writeExternal(element); + myInstance.writeExternal(element); + } + + @Override + public void projectSdkChanged(@Nullable Sdk sdk) { + myInstance.projectSdkChanged(sdk); } } -} \ No newline at end of file + } \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/openapi/roots/LanguageLevelProjectExtension.java b/java/java-psi-api/src/com/intellij/openapi/roots/LanguageLevelProjectExtension.java index dee5fb7de932..f91d24e685e9 100644 --- a/java/java-psi-api/src/com/intellij/openapi/roots/LanguageLevelProjectExtension.java +++ b/java/java-psi-api/src/com/intellij/openapi/roots/LanguageLevelProjectExtension.java @@ -42,7 +42,7 @@ public abstract class LanguageLevelProjectExtension { * @return null if the property is not set yet (e.g. after migration). */ @Nullable - public Boolean isDefault() { + public Boolean getDefault() { return myDefault; } @@ -50,6 +50,10 @@ public abstract class LanguageLevelProjectExtension { myDefault = value; } + public boolean isDefault() { + return myDefault != null && myDefault; + } + public abstract void languageLevelsChanged(); /** diff --git a/java/java-psi-api/src/messages/JavaCoreBundle.properties b/java/java-psi-api/src/messages/JavaCoreBundle.properties index c9646f45f3b0..5ff783532c04 100644 --- a/java/java-psi-api/src/messages/JavaCoreBundle.properties +++ b/java/java-psi-api/src/messages/JavaCoreBundle.properties @@ -1,7 +1,6 @@ psi.error.attempt.to.edit.class.file=Cannot modify compiled element -default.language.level.description=JDK default -default.jdk.level.description=JDK default ({0}) +default.language.level.description=SDK default jdk.1.3.language.level.description=1.3 - Plain old Java jdk.1.4.language.level.description=1.4 - 'assert' keyword jdk.1.5.language.level.description=5.0 - 'enum' keyword, generics, autoboxing etc. diff --git a/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java b/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java index 8a48d8389014..069c08cd3a57 100644 --- a/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java +++ b/java/openapi/src/com/intellij/ide/util/projectWizard/JavaModuleBuilder.java @@ -155,7 +155,7 @@ public class JavaModuleBuilder extends ModuleBuilder implements SourcePathsBuild @Override public List commit(@NotNull Project project, ModifiableModuleModel model, ModulesProvider modulesProvider) { LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(ProjectManager.getInstance().getDefaultProject()); - Boolean aDefault = extension.isDefault(); + Boolean aDefault = extension.getDefault(); LanguageLevelProjectExtension instance = LanguageLevelProjectExtension.getInstance(project); if (aDefault != null && !aDefault) { instance.setLanguageLevel(extension.getLanguageLevel()); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index 9fdc4c29cb0e..6e33cd89b61b 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1453,7 +1453,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { if (myMatchingVisitor.getResult()) { final PsiTypeElement checkType = instanceOf.getCheckType(); if (checkType != null) { - myMatchingVisitor.setResult(matchType(checkType, instanceOf2.getCheckType())); + myMatchingVisitor.setResult(myMatchingVisitor.match(checkType, instanceOf2.getCheckType())); } } } diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java index b3bca3199ed5..94e47f8c1684 100644 --- a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java +++ b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java @@ -173,25 +173,26 @@ public abstract class ProjectWizardTestCase ext ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ProjectJdkTable jdkTable = ProjectJdkTable.getInstance(); - Sdk defaultJdk = new SimpleJavaSdkType().createJdk(DEFAULT_SDK, SystemProperties.getJavaHome()); - Sdk otherJdk = new SimpleJavaSdkType().createJdk("_other", SystemProperties.getJavaHome()); - jdkTable.addJdk(otherJdk); - jdkTable.addJdk(defaultJdk); - mySdks.add(defaultJdk); - mySdks.add(otherJdk); + addSdk(new SimpleJavaSdkType().createJdk(DEFAULT_SDK, SystemProperties.getJavaHome())); + addSdk(new SimpleJavaSdkType().createJdk("_other", SystemProperties.getJavaHome())); //noinspection UseOfSystemOutOrSystemErr - System.out.println(Arrays.asList(jdkTable.getAllJdks())); + System.out.println(Arrays.asList(ProjectJdkTable.getInstance().getAllJdks())); if (getName().contains("DefaultSdk")) { Project defaultProject = ProjectManager.getInstance().getDefaultProject(); - ProjectRootManager.getInstance(defaultProject).setProjectSdk(defaultJdk); + ProjectRootManager.getInstance(defaultProject).setProjectSdk( + new SimpleJavaSdkType().createJdk(DEFAULT_SDK, SystemProperties.getJavaHome())); } } }); } + protected void addSdk(Sdk sdk) { + ProjectJdkTable.getInstance().addJdk(sdk); + mySdks.add(sdk); + } + @Override public void tearDown() throws Exception { if (myWizard != null) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 5ccd42cfd4cb..cebe481c3d1e 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -530,7 +530,7 @@ public abstract class ChooseByNameBase { return; } - if (oppositeComponent != null) { + if (oppositeComponent != null && myProject != null) { ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); ToolWindow toolWindow = toolWindowManager.getToolWindow(toolWindowManager.getActiveToolWindowId()); if (toolWindow != null) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ProfilesConfigurableComboBox.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ProfilesConfigurableComboBox.java index 3e8992f48012..36148ffb920e 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ProfilesConfigurableComboBox.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/ProfilesConfigurableComboBox.java @@ -77,7 +77,12 @@ public abstract class ProfilesConfigurableComboBox extends JPanel { mySaveListener.setDelegate(inputValidator); mySubmitNameComponent.setText(initialValue); myCardLayout.show(myComboBoxPanel, EDIT_CARD); - mySubmitNameComponent.requestFocus(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + mySubmitNameComponent.requestFocus(); + } + }); } public void reset(final Collection profiles) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java index f022a4a92280..db2e8c7a6e84 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -46,6 +46,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.IconUtil; import com.intellij.util.containers.HashMap; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.UiNotifyConnector; @@ -55,7 +56,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.border.EmptyBorder; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; @@ -286,7 +286,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD final JLabel label = new JLabel(description); label.setBorder(BorderFactory.createCompoundBorder( new SideBorder(UIUtil.getPanelBackground().darker(), SideBorder.BOTTOM), - BorderFactory.createEmptyBorder(0, 5, 10, 5))); + JBUI.Borders.empty(0, 5, 10, 5))); return label; } @@ -297,7 +297,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD Disposer.register(myDisposable, myUiUpdater); new UiNotifyConnector(panel, myUiUpdater); - panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + panel.setBorder(JBUI.Borders.empty()); createTree(); @@ -316,7 +316,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD toolbarPanel.add(myTextFieldAction, BorderLayout.EAST); myPathTextFieldWrapper = new JPanel(new BorderLayout()); - myPathTextFieldWrapper.setBorder(new EmptyBorder(0, 0, 2, 0)); + myPathTextFieldWrapper.setBorder(JBUI.Borders.emptyBottom(2)); myPathTextField = new FileTextFieldImpl.Vfs( FileChooserFactoryImpl.getMacroMap(), getDisposable(), new LocalFsFinder.FileChooserFilter(myChooserDescriptor, myFileSystemTree)) { @@ -344,7 +344,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myFileSystemTree.getTree()); //scrollPane.setBorder(BorderFactory.createLineBorder(new Color(148, 154, 156))); panel.add(scrollPane, BorderLayout.CENTER); - panel.setPreferredSize(new Dimension(400, 400)); + panel.setPreferredSize(JBUI.size(400)); panel.add(new JLabel( diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index a1995ad5bb2b..6388c4b08a5d 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -32,6 +32,8 @@ html.inspections.check.image.width.fix.message=Set width value to {0} html.inspections.check.image.height.message=Original image height is {0} html.inspections.check.image.height.fix.message=Set height value to {0} html.inspections.check.deprecated.tag=Deprecated HTML tag +html.intentions.insert.image.size=Insert background-image size +html.intentions.update.image.size=Update background-image size unwrap.enclosing.tag.name.action.name=Remove Enclosing Tag {0} jsp.inspections.group.name=JSP Inspections # color dialog @@ -218,7 +220,7 @@ select.xsd.schema.dialog.title=Select XSD Schema emmet.title=Emmet emmet.update.tag.title=Update tag with Emmet emmet.configuration.title=Emmet -emmet.enable.label=&Enable XML Emmet +emmet.enable.label=&Enable XML/HTML Emmet emmet.filters.enabled.by.default=Filters enabled by default emmet.enable.preview=Enable &abbreviation preview emmet.expand.abbreviation.with=Expand &abbreviation with diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java b/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java index 5b9164fd5579..9358d9242449 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/ex/ProjectRootManagerEx.java @@ -37,7 +37,10 @@ public abstract class ProjectRootManagerEx extends ProjectRootManager { public abstract void clearScopesCachesForModules(); - + /** + * @see ProjectRootManagerEx#addProjectJdkListener(ProjectJdkListener) + * @see ProjectRootManagerEx#removeProjectJdkListener(ProjectJdkListener) + */ public interface ProjectJdkListener extends EventListener { void projectJdkChanged(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index c19ba91e3346..e122fd11c826 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java @@ -504,7 +504,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project return myModuleModel.getModules(); } - private Module[] myCachedSortedModules = null; + private volatile Module[] myCachedSortedModules = null; @Override @NotNull @@ -523,7 +523,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project return myModuleModel.findModuleByName(name); } - private Comparator myCachedModuleComparator = null; + private volatile Comparator myCachedModuleComparator = null; @Override @NotNull @@ -602,7 +602,7 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Project class ModuleModelImpl implements ModifiableModuleModel { final Map myPathToModule = new LinkedHashMap(new EqualityPolicy.ByHashingStrategy(FilePathHashingStrategy.create())); - private Module[] myModulesCache; + private volatile Module[] myModulesCache; private final List myModulesToDispose = new ArrayList(); private final Map myModuleToNewName = new HashMap(); diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/ProjectExtension.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/ProjectExtension.java index f4e5bc76eb0d..7c1c395cc0f6 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/ProjectExtension.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/ProjectExtension.java @@ -21,8 +21,12 @@ package com.intellij.openapi.roots; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.JDOMExternalizable; +import org.jetbrains.annotations.Nullable; public abstract class ProjectExtension implements JDOMExternalizable{ public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.projectExtension"); + + public void projectSdkChanged(@Nullable Sdk sdk) {} } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java index c439a35d0a36..42098948966f 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerImpl.java @@ -231,12 +231,20 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Proj myProjectSdkName = sdk.getName(); myProjectSdkType = sdk.getSdkType().getName(); } + projectJdkChanged(); + } + + private void projectJdkChanged() { mergeRootsChangesDuring(new Runnable() { @Override public void run() { myProjectJdkEventDispatcher.getMulticaster().projectJdkChanged(); } }); + Sdk sdk = getProjectSdk(); + for (ProjectExtension extension : Extensions.getExtensions(ProjectExtension.EP_NAME, myProject)) { + extension.projectSdkChanged(sdk); + } } @Override @@ -244,12 +252,7 @@ public class ProjectRootManagerImpl extends ProjectRootManagerEx implements Proj ApplicationManager.getApplication().assertWriteAccessAllowed(); myProjectSdkName = name; - mergeRootsChangesDuring(new Runnable() { - @Override - public void run() { - myProjectJdkEventDispatcher.getMulticaster().projectJdkChanged(); - } - }); + projectJdkChanged(); } @Override diff --git a/platform/projectModel-impl/src/messages/ProjectBundle.properties b/platform/projectModel-impl/src/messages/ProjectBundle.properties index 4b31b4aaca45..acf81ec454ef 100644 --- a/platform/projectModel-impl/src/messages/ProjectBundle.properties +++ b/platform/projectModel-impl/src/messages/ProjectBundle.properties @@ -246,7 +246,7 @@ libraries.node.text.module=Libraries contain classes that add up various functio \ To attach a library to a module, select that module, click the Dependencies tab, click Add and specify the library location. jdks.node.display.name=SDKs -project.language.level.combo.item= +project.language.level.combo.item=Project default add.action.name=Add new ... add.new.jdk.text=Add New SDK add.new.global.library.text=New Global Library diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 23250d8fe2fe..c57c93805464 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -2476,6 +2476,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "@Deprecated\n" + "package one.two;"; assertEquals("Find annotation on package statement", 1, findMatchesCount(source4, "@'_Annotation", true)); + + final String source5 ="class A {" + + " boolean a(Object o) {" + + " return o instanceof @HH String;" + + " }" + + "}"; + assertEquals("Find annotation on instanceof expression", 1, findMatchesCount(source5, "'_a instanceof @HH String")); + assertEquals("Match annotation correctly on instanceof expression", 0, findMatchesCount(source5, "'_a instanceof @GG String")); } public void testBoxingAndUnboxing() { diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/api/printer/PrintElementGenerator.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/api/printer/PrintElementGenerator.java index 16b787447af0..1ed689cde270 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/api/printer/PrintElementGenerator.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/api/printer/PrintElementGenerator.java @@ -29,6 +29,4 @@ public interface PrintElementGenerator { @NotNull PrintElementWithGraphElement toPrintElementWithGraphElement(@NotNull PrintElement printElement); - - void invalidate(); } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java index bfbd5bc54825..c230e0fc0fa6 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/VisibleGraphImpl.java @@ -142,8 +142,12 @@ public class VisibleGraphImpl implements VisibleGraph { targetId = edge.getTargetId(); } if (edge.getType().isNormalEdge()) { - if (printElementType == DOWN_ARROW) targetId = convertToNodeId(edge.getDownNodeIndex()); - else targetId = convertToNodeId(edge.getUpNodeIndex()); + if (printElementType == DOWN_ARROW) { + targetId = convertToNodeId(edge.getDownNodeIndex()); + } + else { + targetId = convertToNodeId(edge.getUpNodeIndex()); + } } if (targetId == null) return null; @@ -198,7 +202,14 @@ public class VisibleGraphImpl implements VisibleGraph { CommitId commitToJump = null; Integer nodeId = answer.getCommitToJump(); if (nodeId != null) commitToJump = myPermanentGraph.getPermanentCommitsInfo().getCommitId(nodeId); - return new GraphAnswerImpl(answer.getCursorToSet(), commitToJump, answer.getGraphUpdater()); + final Runnable graphUpdater = answer.getGraphUpdater(); + return new GraphAnswerImpl(answer.getCursorToSet(), commitToJump, graphUpdater == null ? null : new Runnable() { + @Override + public void run() { + graphUpdater.run(); + updatePrintElementGenerator(); + } + }); } } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java index 6e9061d54ec4..63bfeaced5c0 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/print/PrintElementGeneratorImpl.java @@ -203,12 +203,6 @@ public class PrintElementGeneratorImpl extends AbstractPrintElementGenerator { result.add(new SimpleRowElement(edge, SimplePrintElement.Type.UP_ARROW, position)); } - @Override - public void invalidate() { - myEdgesInRowGenerator.invalidate(); - cache.clear(); - } - private boolean edgeIsVisibleInRow(@NotNull GraphEdge edge, int visibleRowIndex) { Pair normalEdge = LinearGraphUtils.asNormalEdge(edge); if (normalEdge == null) // e.d. edge is special. See addSpecialEdges diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java index 8a3260ca3ef4..f2e345ce044b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java @@ -17,19 +17,15 @@ import com.intellij.vcs.log.data.VcsLogFilterer; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.graph.PermanentGraph; -import com.intellij.vcs.log.graph.VisibleGraph; import com.intellij.vcs.log.graph.actions.GraphAction; import com.intellij.vcs.log.graph.actions.GraphAnswer; import com.intellij.vcs.log.impl.VcsLogImpl; import com.intellij.vcs.log.ui.frame.MainFrame; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; import com.intellij.vcs.log.ui.tables.GraphTableModel; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import java.awt.*; import java.util.ArrayList; @@ -79,7 +75,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { ApplicationManager.getApplication().assertIsDispatchThread(); PermanentGraph previousPermGraph = myVisiblePack.getPermanentGraph(); - TIntHashSet previouslySelected = getSelectedCommits(); + VcsLogGraphTable.Selection previousSelection = getTable().getSelection(); myVisiblePack = pack; boolean permGraphChanged = previousPermGraph != myVisiblePack.getPermanentGraph(); @@ -90,7 +86,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } else { currentModel.setVisiblePack(myVisiblePack); - restoreSelection(currentModel, myVisiblePack.getVisibleGraph(), previouslySelected, getTable()); + previousSelection.restore(myVisiblePack.getVisibleGraph()); } getTable().setPaintBusy(false); @@ -105,42 +101,6 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return myMainFrame; } - private static void restoreSelection(@NotNull GraphTableModel newModel, - @NotNull VisibleGraph newVisibleGraph, - @NotNull TIntHashSet previouslySelectedCommits, - @NotNull final VcsLogGraphTable table) { - TIntHashSet rowsToSelect = findNewRowsToSelect(newModel, newVisibleGraph, previouslySelectedCommits); - rowsToSelect.forEach(new TIntProcedure() { - @Override - public boolean execute(int row) { - table.addRowSelectionInterval(row, row); - return true; - } - }); - } - - @NotNull - private static TIntHashSet findNewRowsToSelect(@NotNull GraphTableModel newModel, - @NotNull VisibleGraph visibleGraph, - @NotNull TIntHashSet selectedHashes) { - TIntHashSet rowsToSelect = new TIntHashSet(); - if (newModel.getRowCount() == 0) { - // this should have been covered by facade.getVisibleCommitCount, - // but if the table is empty (no commits match the filter), the GraphFacade is not updated, because it can't handle it - // => it has previous values set. - return rowsToSelect; - } - for (int row = 0; - row < visibleGraph.getVisibleCommitCount() && rowsToSelect.size() < selectedHashes.size(); - row++) { //stop iterating if found all hashes - int commit = visibleGraph.getRowInfo(row).getCommit(); - if (selectedHashes.contains(commit)) { - rowsToSelect.add(row); - } - } - return rowsToSelect; - } - public void repaintUI() { myMainFrame.getGraphTable().repaint(); } @@ -156,7 +116,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { public void run() { assert updater != null : "Action:" + title + "\nController: " + myVisiblePack.getVisibleGraph().getActionController() + "\nAnswer:" + answer; updater.run(); - handleAnswer(answer, true); + getTable().handleAnswer(answer, true, null); } }); } @@ -226,31 +186,6 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return future; } - public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange) { - if (dataCouldChange) { - ((AbstractTableModel)(getTable().getModel())).fireTableDataChanged(); - } - - repaintUI(); - - if (answer == null) { - return; - } - - if (answer.getCursorToSet() != null) { - myMainFrame.getGraphTable().setCursor(answer.getCursorToSet()); - } - if (answer.getCommitToJump() != null) { - int row = myVisiblePack.getVisibleGraph().getVisibleRowIndex(answer.getCommitToJump()); - if (row >= 0) { - myMainFrame.getGraphTable().jumpToRow(row); - } - else { - // TODO wait for the full log and then jump - } - } - } - private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter, @NotNull final SettableFuture future) { @@ -327,23 +262,6 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { return myColorManager; } - @NotNull - public TIntHashSet getSelectedCommits() { - int[] selectedRows = getTable().getSelectedRows(); - return getCommitsAtRows(myVisiblePack.getVisibleGraph(), selectedRows); - } - - @NotNull - private static TIntHashSet getCommitsAtRows(@NotNull VisibleGraph graph, int[] rows) { - TIntHashSet commits = new TIntHashSet(); - for (int row : rows) { - if (row < graph.getVisibleCommitCount()) { - commits.add(graph.getRowInfo(row).getCommit()); - } - } - return commits; - } - public void applyFiltersAndUpdateUi() { VcsLogFilterCollection filters = myMainFrame.getFilterUi().getFilters(); myFilterer.onFiltersChange(filters); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index 933fe986b943..ab79d9af9be1 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -38,10 +38,7 @@ import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsLogHighlighter; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VisiblePack; -import com.intellij.vcs.log.graph.ColorGenerator; -import com.intellij.vcs.log.graph.PrintElement; -import com.intellij.vcs.log.graph.RowInfo; -import com.intellij.vcs.log.graph.RowType; +import com.intellij.vcs.log.graph.*; import com.intellij.vcs.log.graph.actions.GraphAction; import com.intellij.vcs.log.graph.actions.GraphAnswer; import com.intellij.vcs.log.printer.idea.GraphCellPainter; @@ -52,11 +49,14 @@ import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.render.GraphCommitCell; import com.intellij.vcs.log.ui.render.GraphCommitCellRender; import com.intellij.vcs.log.ui.tables.GraphTableModel; +import gnu.trove.TIntHashSet; +import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import sun.swing.table.DefaultTableCellHeaderRenderer; import javax.swing.*; +import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.TableModelEvent; @@ -65,9 +65,7 @@ import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; +import java.util.*; import java.util.List; import static com.intellij.vcs.log.printer.idea.PrintParameters.HEIGHT_CELL; @@ -85,6 +83,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @NotNull private final VcsLogUiImpl myUI; private final VcsLogDataHolder myLogDataHolder; private final GraphCommitCellRender myGraphCommitCellRender; + private final MyDummyTableCellEditor myDummyEditor = new MyDummyTableCellEditor(); private boolean myColumnsSizeInitialized = false; @@ -364,6 +363,103 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C }); } + public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange, @Nullable Selection previousSelection) { + if (dataCouldChange) { + GraphTableModel graphTableModel = (GraphTableModel)getModel(); + + graphTableModel.fireTableDataChanged(); + + // since fireTableDataChanged clears selection we restore it here + if (previousSelection != null) { + previousSelection.restore(myDataPack.getVisibleGraph()); + } + } + + myUI.repaintUI(); // in case of repaintUI doing something more than just repainting this table in some distant future + + if (answer == null) { + return; + } + + if (answer.getCursorToSet() != null) { + setCursor(answer.getCursorToSet()); + } + if (answer.getCommitToJump() != null) { + Integer row = myDataPack.getVisibleGraph().getVisibleRowIndex(answer.getCommitToJump()); + if (row != null && row >= 0) { + jumpToRow(row); + } + // TODO wait for the full log and then jump + } + } + + private GraphTableModel getGraphTableModel() { + return (GraphTableModel)getModel(); + } + + @NotNull + public Selection getSelection() { + return new Selection(); + } + + public class Selection { + private final TIntHashSet myCommits; + + public Selection() { + myCommits = getCommitsAtRows(myDataPack.getVisibleGraph(), getSelectedRows()); + } + + public void restore(@NotNull VisibleGraph newVisibleGraph) { + TIntHashSet rowsToSelect = findNewRowsToSelect(getGraphTableModel(), newVisibleGraph, myCommits); + if (!rowsToSelect.isEmpty()) { + rowsToSelect.forEach(new TIntProcedure() { + @Override + public boolean execute(int row) { + addRowSelectionInterval(row, row); + return true; + } + }); + } + // sometimes commits that were selected are now collapsed + // currently in this case selection disappears + // in the future we need to create a method in LinearGraphController that allows to calculate visible commit for our commit + // or answer from collapse action could return a map that gives us some information about what commits were collapsed and where + } + + @NotNull + private TIntHashSet findNewRowsToSelect(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph visibleGraph, + @NotNull TIntHashSet selectedHashes) { + TIntHashSet rowsToSelect = new TIntHashSet(); + if (newModel.getRowCount() == 0) { + // this should have been covered by facade.getVisibleCommitCount, + // but if the table is empty (no commits match the filter), the GraphFacade is not updated, because it can't handle it + // => it has previous values set. + return rowsToSelect; + } + for (int row = 0; + row < visibleGraph.getVisibleCommitCount() && rowsToSelect.size() < selectedHashes.size(); + row++) { //stop iterating if found all hashes + int commit = visibleGraph.getRowInfo(row).getCommit(); + if (selectedHashes.contains(commit)) { + rowsToSelect.add(row); + } + } + return rowsToSelect; + } + + @NotNull + private TIntHashSet getCommitsAtRows(@NotNull VisibleGraph graph, int[] rows) { + TIntHashSet commits = new TIntHashSet(); + for (int row : rows) { + if (row < graph.getVisibleCommitCount()) { + commits.add(graph.getRowInfo(row).getCommit()); + } + } + return commits; + } + } + private class MyHeaderMouseAdapter extends MouseAdapter { @Override public void mouseMoved(MouseEvent e) { @@ -423,11 +519,13 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C Collection printElements = myDataPack.getVisibleGraph().getRowInfo(row).getPrintElements(); PrintElement printElement = myGraphCellPainter.mouseOver(printElements, point.x, point.y); + Selection previousSelection = getSelection(); GraphAnswer answer = myDataPack.getVisibleGraph().getActionController().performAction(new GraphAction.GraphActionImpl(printElement, actionType)); - myUI.handleAnswer(answer, actionType == GraphAction.Type.MOUSE_CLICK && printElement != null); + handleAnswer(answer, actionType == GraphAction.Type.MOUSE_CLICK && printElement != null, previousSelection); } + private boolean isAboveLink(MouseEvent e) { return myLinkListener.getTagAt(e) != null; } @@ -532,6 +630,13 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } } + @Override + public TableCellEditor getCellEditor() { + // this fixes selection problems by prohibiting selection when user clicks on graph (CellEditor does that) + // what is fun about this code is that if you set cell editor in constructor with setCellEditor method it would not work + return myDummyEditor; + } + private class StringCellRenderer extends ColoredTableCellRenderer { @Override protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) { @@ -577,4 +682,55 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } } + private class MyDummyTableCellEditor implements TableCellEditor { + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + return null; + } + + @Override + public Object getCellEditorValue() { + return null; + } + + @Override + public boolean isCellEditable(EventObject anEvent) { + return false; + } + + @Override + public boolean shouldSelectCell(EventObject anEvent) { + if (!(anEvent instanceof MouseEvent)) return true; + MouseEvent e = (MouseEvent)anEvent; + + int row = PositionUtil.getRowIndex(e.getPoint()); + if (row > getRowCount() - 1) { + return false; + } + Point point = calcPoint4Graph(e.getPoint()); + Collection printElements = myDataPack.getVisibleGraph().getRowInfo(row).getPrintElements(); + PrintElement printElement = myGraphCellPainter.mouseOver(printElements, point.x, point.y); + return printElement == null; + } + + @Override + public boolean stopCellEditing() { + return false; + } + + @Override + public void cancelCellEditing() { + + } + + @Override + public void addCellEditorListener(CellEditorListener l) { + + } + + @Override + public void removeCellEditorListener(CellEditorListener l) { + + } + } } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueNode.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueNode.java index e50de966192d..5d63f0beddb5 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueNode.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public interface XValueNode extends Obsolescent { * If value text exceeds this constant it's recommended to truncate it and use {@link #setFullValueEvaluator(XFullValueEvaluator)} method * to provide full value */ - int MAX_VALUE_LENGTH = 100; + int MAX_VALUE_LENGTH = 1000; /** * Setup presentation of the value diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java index 43f159e5b6db..c4c7ab6a148b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java @@ -40,6 +40,7 @@ import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory; import com.intellij.xdebugger.impl.breakpoints.ui.XLightBreakpointPropertiesPanel; +import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -127,7 +128,7 @@ public class DebuggerUIUtil { JComponent component, @Nullable final FullValueEvaluationCallbackImpl callback) { ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null); - builder.setResizable(true)/*.setAlpha(1)*/ // alpha disabled because of IDEA-136331 + builder.setResizable(true) .setMovable(true) .setDimensionServiceKey(project, FULL_VALUE_POPUP_DIMENSION_KEY, false) .setRequestFocus(false); @@ -328,4 +329,14 @@ public class DebuggerUIUtil { return myObsolete.get(); } } + + @Nullable + public static String getNodeRawValue(@NotNull XValueNodeImpl valueNode) { + if (valueNode.getValueContainer() instanceof XValueTextProvider) { + return ((XValueTextProvider)valueNode.getValueContainer()).getValueText(); + } + else { + return valueNode.getRawValue(); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java index ee95281b6c9d..e8b6008656d1 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTreeRenderer.java @@ -15,18 +15,24 @@ */ package com.intellij.xdebugger.impl.ui.tree; +import com.intellij.openapi.project.Project; import com.intellij.ui.AbstractExpandableItemsHandler; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ui.JBInsets; +import com.intellij.xdebugger.XDebuggerBundle; +import com.intellij.xdebugger.frame.ImmediateFullValueEvaluator; import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; +import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; +import java.awt.event.MouseEvent; /** * @author nik @@ -37,6 +43,8 @@ class XDebuggerTreeRenderer extends ColoredTreeCellRenderer { private int myLinkOffset; private int myLinkWidth; + private final MyLongTextHyperlink myLongTextLink = new MyLongTextHyperlink(); + public XDebuggerTreeRenderer() { Insets myLinkIpad = myLink.getIpad(); myLink.setIpad(new JBInsets(myLinkIpad.top, 0, myLinkIpad.bottom, myLinkIpad.right)); @@ -56,18 +64,38 @@ class XDebuggerTreeRenderer extends ColoredTreeCellRenderer { XDebuggerTreeNode node = (XDebuggerTreeNode)value; node.appendToComponent(this); setIcon(node.getIcon()); + + Rectangle treeVisibleRect = tree.getVisibleRect(); + TreePath path = tree.getPathForRow(row); + int rowX = path != null ? ((XDebuggerTree.LinkTreeUI)tree.getUI()).getRowX(row, path.getPathCount() - 1) : 0; + if (myHaveLink) { - Dimension linkSize = myLink.getPreferredSize(); - myLinkWidth = linkSize.width; - myLink.setBounds(0, 0, linkSize.width, linkSize.height); - Rectangle treeVisibleRect = tree.getVisibleRect(); - TreePath path = tree.getPathForRow(row); - int rowX = path != null ? ((XDebuggerTree.LinkTreeUI)tree.getUI()).getRowX(row, path.getPathCount() - 1) : 0; - myLinkOffset = Math.min(super.getPreferredSize().width, treeVisibleRect.x + treeVisibleRect.width - myLinkWidth - rowX); + setupLinkDimensions(treeVisibleRect, rowX); + } + else { + if (rowX + super.getPreferredSize().width > treeVisibleRect.x + treeVisibleRect.width) { + // text does not fit visible area - show link + if (node instanceof XValueNodeImpl) { + final String rawValue = DebuggerUIUtil.getNodeRawValue((XValueNodeImpl)node); + if (rawValue != null) { + myLongTextLink.setupComponent(rawValue, ((XDebuggerTree)tree).getProject()); + append(myLongTextLink.getLinkText(), myLongTextLink.getTextAttributes(), myLongTextLink); + setupLinkDimensions(treeVisibleRect, rowX); + myLinkWidth = 0; + } + } + } } putClientProperty(AbstractExpandableItemsHandler.DISABLE_EXPANDABLE_HANDLER, myHaveLink ? true : null); } + private void setupLinkDimensions(Rectangle treeVisibleRect, int rowX) { + Dimension linkSize = myLink.getPreferredSize(); + myLinkWidth = linkSize.width; + myLink.setBounds(0, 0, linkSize.width, linkSize.height); + myLinkOffset = Math.min(super.getPreferredSize().width, treeVisibleRect.x + treeVisibleRect.width - myLinkWidth - rowX); + } + @Override public void append(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, Object tag) { if (tag instanceof XDebuggerTreeNodeHyperlink && ((XDebuggerTreeNodeHyperlink)tag).alwaysOnScreen()) { @@ -131,4 +159,29 @@ class XDebuggerTreeRenderer extends ColoredTreeCellRenderer { super.doPaint(g); } } + + private static class MyLongTextHyperlink extends XDebuggerTreeNodeHyperlink { + private String myText; + private Project myProject; + + public MyLongTextHyperlink() { + super(XDebuggerBundle.message("node.test.show.full.value")); + } + + public void setupComponent(String text, Project project) { + myText = text; + myProject = project; + } + + @Override + public boolean alwaysOnScreen() { + return true; + } + + @Override + public void onClick(MouseEvent event) { + DebuggerUIUtil.showValuePopup(new ImmediateFullValueEvaluator(myText), event, myProject, null); + event.consume(); + } + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java index e155ee5a02ad..bd7c2ff75200 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java @@ -23,7 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.AppUIUtil; import com.intellij.util.SmartList; import com.intellij.xdebugger.frame.XFullValueEvaluator; -import com.intellij.xdebugger.impl.ui.XValueTextProvider; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import com.intellij.xdebugger.impl.ui.tree.nodes.HeadlessValueEvaluationCallback; import com.intellij.xdebugger.impl.ui.tree.nodes.WatchMessageNode; @@ -76,14 +76,7 @@ public abstract class XFetchValueActionBase extends AnAction { XValueNodeImpl valueNode = (XValueNodeImpl)node; XFullValueEvaluator fullValueEvaluator = valueNode.getFullValueEvaluator(); if (fullValueEvaluator == null || !fullValueEvaluator.isShowValuePopup()) { - String rawValue; - if (valueNode.getValueContainer() instanceof XValueTextProvider) { - rawValue = ((XValueTextProvider)valueNode.getValueContainer()).getValueText(); - } - else { - rawValue = valueNode.getRawValue(); - } - valueCollector.add(StringUtil.notNullize(rawValue)); + valueCollector.add(StringUtil.notNullize(DebuggerUIUtil.getNodeRawValue(valueNode))); } else { new CopyValueEvaluationCallback(valueNode, valueCollector).startFetchingValue(fullValueEvaluator); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java index cac417a1fd39..782f10c65d49 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java @@ -701,6 +701,7 @@ public class GroovyTypeCheckVisitor extends BaseInspectionVisitor { } private void registerCannotApplyError(@NotNull String invokedText, @NotNull CallInfo info) { + if (info.getArgumentTypes() == null) return; final String typesString = buildArgTypesList(info.getArgumentTypes()); registerError( info.getElementToHighlight(), @@ -839,12 +840,14 @@ public class GroovyTypeCheckVisitor extends BaseInspectionVisitor { public void visitCastExpression(GrTypeCastExpression expression) { super.visitCastExpression(expression); - if (expression.getCastTypeElement() == null) return; - final PsiType expectedType = expression.getCastTypeElement().getType(); final GrExpression operand = expression.getOperand(); + if (operand == null) return; final PsiType actualType = operand.getType(); if (actualType == null) return; + if (expression.getCastTypeElement() == null) return; + final PsiType expectedType = expression.getCastTypeElement().getType(); + final ConversionResult result = TypesUtil.canCast(expectedType, actualType, expression); if (result == ConversionResult.OK) return; final ProblemHighlightType highlightType = result == ConversionResult.ERROR diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrTypeCastExpression.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrTypeCastExpression.java index b4fe54f956bd..6cccb4832cc3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrTypeCastExpression.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrTypeCastExpression.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.annotations.NotNull; import com.intellij.psi.PsiElement; @@ -26,6 +27,7 @@ import com.intellij.psi.PsiElement; public interface GrTypeCastExpression extends GrExpression { GrTypeElement getCastTypeElement(); + @Nullable GrExpression getOperand(); @NotNull diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrTypeCastExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrTypeCastExpressionImpl.java index 54665477304c..06f8ed1e356e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrTypeCastExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrTypeCastExpressionImpl.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -58,6 +59,7 @@ public class GrTypeCastExpressionImpl extends GrExpressionImpl implements GrType } @Override + @Nullable public GrExpression getOperand() { return findExpressionChild(this); } diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOutputParser.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOutputParser.java index a0e2a97fd94f..c85d5e8bd92e 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOutputParser.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovycOutputParser.java @@ -184,6 +184,10 @@ public abstract class GroovycOutputParser { LOG.debug("Error message: " + message); return true; } + if (message.getMessageText().contains(GroovyRtConstants.GROOVYC_STUB_GENERATION_FAILED)) { + LOG.debug("Stub failed message: " + message); + return true; + } } if (getStdErr().length() > 0) { LOG.debug("Non-empty stderr: '" + getStdErr() + "'"); diff --git a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java index 855b27722595..6a37194597f9 100644 --- a/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java +++ b/plugins/groovy/rt-constants/src/org/jetbrains/groovy/compiler/rt/GroovyRtConstants.java @@ -35,4 +35,5 @@ public class GroovyRtConstants { public static final String CLEAR_PRESENTABLE = "$@#$%^ CLEAR_PRESENTABLE"; public static final String NO_GROOVY = "Cannot compile Groovy files: no Groovy library is defined"; public static final String OPTIMIZE = "optimize"; + public static final String GROOVYC_STUB_GENERATION_FAILED = "Groovyc stub generation failed"; } diff --git a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerWrapper.java b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerWrapper.java index 369a112d62eb..6824474b7394 100644 --- a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerWrapper.java +++ b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovyCompilerWrapper.java @@ -194,7 +194,7 @@ public class GroovyCompilerWrapper { if (forStubs) { collector.add(new CompilerMessage(GroovyCompilerMessageCategories.INFORMATION, - "Groovyc stub generation failed", null, -1, -1)); + GroovyRtConstants.GROOVYC_STUB_GENERATION_FAILED, null, -1, -1)); } final StringWriter writer = new StringWriter(); diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java index a3a94c8f7f18..3590681522f8 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java @@ -33,7 +33,10 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.reference.SoftLazyValue; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; @@ -47,29 +50,54 @@ import java.util.*; * Date: 7/26/11 */ public class XmlPropertiesFileImpl extends XmlPropertiesFile { - private static final Key> KEY = Key.create("xml properties file"); private final XmlFile myFile; - private final SoftLazyValue> myPropertiesMap = new SoftLazyValue>() { + private final SoftLazyValue myInfo = new SoftLazyValue() { @NotNull @Override - protected MultiMap compute() { - XmlTag rootTag = myFile.getRootTag(); - if (rootTag == null) { - return MultiMap.emptyInstance(); - } - - XmlTag[] entries = rootTag.findSubTags("entry"); - MultiMap map = new MultiMap(); - - for (XmlTag entry : entries) { - XmlProperty property = new XmlProperty(entry, XmlPropertiesFileImpl.this); - map.putValue(property.getKey(), property); - } - return map; + protected Info compute() { + return new Info(); } }; + private class Info { + private final MultiMap myPropertiesMap = MultiMap.create(); + private List myPropertiesOrder; + private boolean mySorted; + + public Info() { + XmlTag rootTag = myFile.getRootTag(); + final List propertiesOrder = new ArrayList(); + if (rootTag != null) { + XmlTag[] entries = rootTag.findSubTags("entry"); + for (XmlTag entry : entries) { + XmlProperty property = new XmlProperty(entry, XmlPropertiesFileImpl.this); + propertiesOrder.add(property); + myPropertiesMap.putValue(property.getKey(), property); + } + } + mySorted = PropertiesImplUtil.isAlphaSorted(propertiesOrder); + myPropertiesOrder = mySorted ? propertiesOrder : null; + } + + public void setSorted(boolean sorted) { + mySorted = sorted; + myPropertiesOrder = null; + } + + public MultiMap getPropertiesMap() { + return myPropertiesMap; + } + + public List getPropertiesOrder() { + return myPropertiesOrder; + } + + public boolean isSorted() { + return mySorted; + } + } + private XmlPropertiesFileImpl(XmlFile file) { myFile = file; } @@ -83,19 +111,19 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { @NotNull @Override public List getProperties() { - return new ArrayList(myPropertiesMap.getValue().values()); + return new ArrayList(myInfo.getValue().getPropertiesMap().values()); } @Override public IProperty findPropertyByKey(@NotNull @NonNls String key) { - Collection properties = myPropertiesMap.getValue().get(key); + Collection properties = myInfo.getValue().getPropertiesMap().get(key); return properties.isEmpty() ? null : properties.iterator().next(); } @NotNull @Override public List findPropertiesByKey(@NotNull @NonNls String key) { - return new ArrayList(myPropertiesMap.getValue().get(key)); + return new ArrayList(myInfo.getValue().getPropertiesMap().get(key)); } @NotNull @@ -122,22 +150,62 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { @Override public IProperty addPropertyAfter(String key, String value, Property anchor) { - return null; + return addPropertyAfterAndCheckAlphaSorting(key, value, anchor, true, true); + } + + @NotNull + public IProperty addPropertyAfterAndCheckAlphaSorting(String key, String value, @Nullable IProperty anchor, boolean addToEnd, boolean checkAlphaSorting) { + final XmlTag anchorTag = anchor == null ? null : (XmlTag)anchor.getPsiElement(); + final XmlTag rootTag = myFile.getRootTag(); + final XmlTag entry = createPropertyTag(key, value); + final XmlTag addedEntry = (XmlTag) (anchorTag == null ? myFile.getRootTag().addSubTag(entry, !addToEnd) : rootTag.addAfter(entry, anchorTag)); + final XmlProperty property = new XmlProperty(addedEntry, this); + myInfo.getValue().getPropertiesMap().putValue(key, property); + if (checkAlphaSorting) { + checkAlphaSorting(property); + } + return property; } @NotNull @Override public IProperty addProperty(String key, String value) { + final XmlTag entry = createPropertyTag(key, value); + if (myInfo.getValue().isSorted()) { + final XmlProperty dummyProperty = new XmlProperty(entry, this); + final int insertIndex = Collections.binarySearch(myInfo.getValue().getPropertiesOrder(), dummyProperty, new Comparator() { + @Override + public int compare(IProperty p1, IProperty p2) { + final String k1 = p1.getKey(); + final String k2 = p2.getKey(); + return k1.compareTo(k2); + } + }); + final IProperty insertPosition; + final IProperty inserted; + if (insertIndex == -1) { + inserted = addPropertyAfterAndCheckAlphaSorting(key, value, null, false, false); + myInfo.getValue().getPropertiesOrder().add(0, inserted); + } + else { + final int position = insertIndex < 0 ? -insertIndex - 2 : insertIndex; + insertPosition = myInfo.getValue().getPropertiesOrder().get(position); + inserted = addPropertyAfterAndCheckAlphaSorting(key, value, insertPosition, false, false); + myInfo.getValue().getPropertiesOrder().add(position + 1, inserted); + } + return inserted; + } else { + return addPropertyAfterAndCheckAlphaSorting(key, value, null, true, false); + } + } + + private XmlTag createPropertyTag(final String key, final String value) { XmlTag rootTag = myFile.getRootTag(); XmlTag entry = rootTag.createChildTag("entry", "", value, false); entry.setAttribute("key", key); - rootTag.addSubTag(entry, false); - final XmlProperty property = new XmlProperty(entry, this); - myPropertiesMap.getValue().putValue(key, property); - return property; + return entry; } - public static PropertiesFile getPropertiesFile(final PsiFile file) { CachedValuesManager manager = CachedValuesManager.getManager(file.getProject()); if (file instanceof XmlFile) { @@ -194,7 +262,7 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { @Override public boolean isAlphaSorted() { - return PropertiesImplUtil.isAlphaSorted(getProperties()); + return myInfo.getValue().isSorted(); } @Override @@ -213,4 +281,29 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { public int hashCode() { return myFile.hashCode(); } + + private void checkAlphaSorting(final IProperty property) { + if (myInfo.getValue().isSorted()) { + final String key = property.getKey(); + final XmlTag prev = getSibling((XmlTag)property.getPsiElement(), true); + final String prevKey = prev == null ? null : new XmlProperty(prev, this).getKey(); + if (prevKey != null && key != null && prevKey.compareTo(key) > 0) { + myInfo.getValue().setSorted(false); + } else { + final XmlTag next = getSibling((XmlTag)property.getPsiElement(), false); + final String nextKey = next == null ? null : new XmlProperty(next, this).getKey(); + if (nextKey != null && key != null && nextKey.compareTo(key) < 0) { + myInfo.getValue().setSorted(false); + } + } + } + } + + private static XmlTag getSibling(final XmlTag entry, final boolean prev) { + XmlTag sibling = (XmlTag)(prev ? entry.getPrevSibling() : entry.getNextSibling()); + while (sibling != null && !"entry".equals(sibling.getName())) { + sibling = (XmlTag)(prev ? sibling.getPrevSibling() : sibling.getNextSibling()); + } + return sibling; + } } diff --git a/plugins/properties/testData/xml/bar.xml b/plugins/properties/testData/xml/bar.xml new file mode 100644 index 000000000000..b85abb53cc8e --- /dev/null +++ b/plugins/properties/testData/xml/bar.xml @@ -0,0 +1,7 @@ + + + + Hi + bar + baz + \ No newline at end of file diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/xml/XmlPropertiesTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/xml/XmlPropertiesTest.java index d16eaf352f38..fd4b1212107f 100644 --- a/plugins/properties/testSrc/com/intellij/lang/properties/xml/XmlPropertiesTest.java +++ b/plugins/properties/testSrc/com/intellij/lang/properties/xml/XmlPropertiesTest.java @@ -9,6 +9,8 @@ import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.PsiFile; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import java.util.List; @@ -81,6 +83,23 @@ public class XmlPropertiesTest extends LightPlatformCodeInsightFixtureTestCase { assertEquals("vvv", property2.getValue()); } + public void testAddPropertyInAlphaOrder() { + final PsiFile psiFile = myFixture.configureByFile("bar.xml"); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(psiFile); + assertNotNull(propertiesFile); + + WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { + public void run() { + propertiesFile.addProperty("d", "vvv"); + propertiesFile.addProperty("a", "vvv"); + propertiesFile.addProperty("l", "vvv"); + propertiesFile.addProperty("v", "vvv"); + } + }); + assertTrue(propertiesFile.isAlphaSorted()); + assertTrue(PropertiesImplUtil.getPropertiesFile(psiFile).isAlphaSorted()); + } + @Override protected String getTestDataPath() { return PluginPathManager.getPluginHomePath("properties") + "/testData/xml/"; diff --git a/python/helpers/pycharm/django_manage_commands_provider/_optparse.py b/python/helpers/pycharm/django_manage_commands_provider/_optparse.py index 16617ab40fcb..5680b80569c6 100644 --- a/python/helpers/pycharm/django_manage_commands_provider/_optparse.py +++ b/python/helpers/pycharm/django_manage_commands_provider/_optparse.py @@ -24,17 +24,26 @@ def report_data(dumper): command = utility.fetch_command(command_name) assert isinstance(command, BaseCommand) dumper.start_command(command_name=command_name, - command_help_text=str(command.usage("").replace("%prog", command_name)), # TODO: support subcommands + command_help_text=str(command.usage("").replace("%prog", command_name)), + # TODO: support subcommands command_args_text=str(command.args)) for opt in command.option_list: - opt_type = opt.type if opt.type in Option.TYPES else "" # Empty for unknown + num_of_args = int(opt.nargs) if opt.nargs else 0 + opt_type = None + if num_of_args > 0: + # If option accepts arg, we need to determine its type. It could be int, choices, or something other + # See https://docs.python.org/2/library/optparse.html#standard-option-types + if opt.type in ["int", "long"]: + opt_type = "int" + elif opt.choices: + assert isinstance(opt.choices, list), "Choices should be list" + opt_type = opt.choices + # There is no official way to access this field, so I use protected one. At least it is public API. # noinspection PyProtectedMember dumper.add_command_option( - opt_type=opt_type, - choices=opt.choices, long_opt_names=opt._long_opts, short_opt_names=opt._short_opts, help_text=opt.help, - num_of_args=opt.nargs) + argument_info=(num_of_args, opt_type) if num_of_args else None) dumper.close_command() \ No newline at end of file diff --git a/python/helpers/pycharm/django_manage_commands_provider/_xml.py b/python/helpers/pycharm/django_manage_commands_provider/_xml.py index 40260a01ab83..4f034026dd4d 100644 --- a/python/helpers/pycharm/django_manage_commands_provider/_xml.py +++ b/python/helpers/pycharm/django_manage_commands_provider/_xml.py @@ -6,13 +6,17 @@ It does not have schema (yet!) but here is XML format it uses. -- root -- info about command - +"option_type" is only set if "numberOfArgs" > 0, and it can be: "int" (means integer), +"choices" (means opt can have one of the values, provided in choices) or "str" that means "string" (option may have any value) + Classes like DjangoCommandsInfo is used on Java side. """ @@ -77,35 +81,45 @@ class XmlDumper(object): self.__command_element.setAttribute("args", command_args_text) self.__root.appendChild(self.__command_element) - def add_command_option(self, opt_type, choices, long_opt_names, short_opt_names, help_text, num_of_args): + def add_command_option(self, long_opt_names, short_opt_names, help_text, argument_info): """ Adds command option - :param opt_type: "string", "int", "long", "float", "complex", "choice" - :param choices: list of choices for "choice" type + :param argument_info: None if option does not accept any arguments or tuple of (num_of_args, type_info) \ + where num_of_args is int > 0 and type_info is str, representing type (only "int" and "string" are supported) \ + or list of available types in case of choices + :param long_opt_names: list of long opt names :param short_opt_names: list of short opt names :param help_text: help text - :param num_of_args: number of arguments - :type opt_type str - :type choices list of string :type long_opt_names list of str :type short_opt_names list of str :type help_text str - :type num_of_args int + :type argument_info tuple """ assert isinstance(self.__command_element, Element), "Add option in command only" - option = self.__document.createElement("option") - option.setAttribute("type", opt_type) - if choices: - self.__create_text_array(option, "choices", choices) + option = self.__document.createElement("option") + + opt_type_to_report = None + num_of_args = 0 + + if argument_info: + (num_of_args, type_info) = argument_info + if isinstance(type_info, list): + self.__create_text_array(option, "choices", type_info) + opt_type_to_report = "choices" + else: + opt_type_to_report = "int" if str(type_info) == "int" else "str" + if long_opt_names: self.__create_text_array(option, "longNames", long_opt_names) if short_opt_names: self.__create_text_array(option, "shortNames", short_opt_names) + if opt_type_to_report: + option.setAttribute("type", opt_type_to_report) option.setAttribute("help", help_text) if num_of_args: option.setAttribute("numberOfArgs", str(num_of_args)) diff --git a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Argument.java b/python/src/com/jetbrains/python/commandInterface/command/Argument.java similarity index 96% rename from python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Argument.java rename to python/src/com/jetbrains/python/commandInterface/command/Argument.java index fc3f64192c17..4e33c3b585e9 100644 --- a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Argument.java +++ b/python/src/com/jetbrains/python/commandInterface/command/Argument.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jetbrains.python.commandInterface.commandBasedChunkDriver; +package com.jetbrains.python.commandInterface.command; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/ArgumentsInfo.java b/python/src/com/jetbrains/python/commandInterface/command/ArgumentsInfo.java similarity index 95% rename from python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/ArgumentsInfo.java rename to python/src/com/jetbrains/python/commandInterface/command/ArgumentsInfo.java index ad43da45adcd..c1eb793702e9 100644 --- a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/ArgumentsInfo.java +++ b/python/src/com/jetbrains/python/commandInterface/command/ArgumentsInfo.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jetbrains.python.commandInterface.commandBasedChunkDriver; +package com.jetbrains.python.commandInterface.command; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.Nullable; diff --git a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Command.java b/python/src/com/jetbrains/python/commandInterface/command/Command.java similarity index 87% rename from python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Command.java rename to python/src/com/jetbrains/python/commandInterface/command/Command.java index 694021964fea..2d15d152c3c1 100644 --- a/python/src/com/jetbrains/python/commandInterface/commandBasedChunkDriver/Command.java +++ b/python/src/com/jetbrains/python/commandInterface/command/Command.java @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.jetbrains.python.commandInterface.commandBasedChunkDriver; +package com.jetbrains.python.commandInterface.command; import com.intellij.openapi.module.Module; import com.jetbrains.python.commandLineParser.CommandLineParseResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** - * Command with arguments + * Command with arguments and options * * @author Ilya.Kazakevich */ @@ -47,6 +49,12 @@ public interface Command { @NotNull ArgumentsInfo getArgumentsInfo(); + /** + * @return command options + */ + @NotNull + List