diff --git a/java/java-tests/testData/codeInsight/folding/FoldingException2Test.java b/java/java-tests/testData/codeInsight/folding/FoldingException2Test.java new file mode 100644 index 000000000000..f8098abc2f1d --- /dev/null +++ b/java/java-tests/testData/codeInsight/folding/FoldingException2Test.java @@ -0,0 +1,6 @@ +public class Test { + + @SuppressWarnings("unused") void m() { + System.out.println(); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/richcopy/view/RtfTransferableData.java b/platform/lang-impl/src/com/intellij/openapi/editor/richcopy/view/RtfTransferableData.java index 5e86c31cc7f7..34194209f650 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/richcopy/view/RtfTransferableData.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/richcopy/view/RtfTransferableData.java @@ -86,15 +86,17 @@ public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransfera } private static void rectangularBackground(@NotNull SyntaxInfo syntaxInfo, @NotNull StringBuilder buffer, @NotNull Runnable next) { - buffer.append("\n\\s0\\box").append("\\cbpat").append(syntaxInfo.getDefaultBackground()); - saveBackground(buffer, syntaxInfo.getDefaultBackground()); - buffer.append("\\fs").append(syntaxInfo.getSingleFontSize() * 2).append('\n'); + buffer.append("\n\\s0\\box") + .append("\\cbpat").append(syntaxInfo.getDefaultBackground()) + .append("\\cb").append(syntaxInfo.getDefaultBackground()); + addFontSize(buffer, syntaxInfo.getSingleFontSize()); + buffer.append('\n'); next.run(); buffer.append("\\par"); } private static void content(@NotNull SyntaxInfo syntaxInfo, @NotNull StringBuilder buffer, @NotNull String rawText, int maxLength) { - MyVisitor visitor = new MyVisitor(buffer, rawText); + MyVisitor visitor = new MyVisitor(buffer, rawText, syntaxInfo); SyntaxInfo.MarkupIterator it = syntaxInfo.new MarkupIterator(); try { while(it.hasNext()) { @@ -110,8 +112,8 @@ public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransfera } } - private static void saveBackground(@NotNull StringBuilder buffer, int id) { - buffer.append("\\cb").append(id); + private static void addFontSize(StringBuilder buffer, int fontSize) { + buffer.append("\\fs").append(fontSize * 2); } private static class MyVisitor implements MarkupHandler { @@ -119,9 +121,18 @@ public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransfera @NotNull private final StringBuilder myBuffer; @NotNull private final String myRawText; - MyVisitor(@NotNull StringBuilder buffer, @NotNull String rawText) { + private final int myDefaultBackgroundId; + private final int myFontSize; + private int myForegroundId = -1; + private int myFontNameId = -1; + private int myFontStyle = -1; + + MyVisitor(@NotNull StringBuilder buffer, @NotNull String rawText, @NotNull SyntaxInfo syntaxInfo) { myBuffer = buffer; myRawText = rawText; + + myDefaultBackgroundId = syntaxInfo.getDefaultBackground(); + myFontSize = syntaxInfo.getSingleFontSize(); } @Override @@ -152,18 +163,39 @@ public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransfera } @Override - public void handleForeground(int foregroundId) throws Exception { - myBuffer.append("\\cf").append(foregroundId); + public void handleBackground(int backgroundId) throws Exception { + if (backgroundId == myDefaultBackgroundId) { + myBuffer.append("\\plain"); // we cannot use \chcbpat with default background id, as it doesn't work in MS Word, + // and we cannot use \chcbpat0 as it doesn't work in OpenOffice + + addFontSize(myBuffer, myFontSize); + if (myFontNameId >= 0) { + handleFont(myFontNameId); + } + if (myForegroundId >= 0) { + handleForeground(myForegroundId); + } + if (myFontStyle >= 0) { + handleStyle(myFontStyle); + } + } + else { + myBuffer.append("\\chcbpat").append(backgroundId); + } + myBuffer.append("\\cb").append(backgroundId); + myBuffer.append('\n'); } @Override - public void handleBackground(int backgroundId) throws Exception { - saveBackground(myBuffer, backgroundId); + public void handleForeground(int foregroundId) throws Exception { + myBuffer.append("\\cf").append(foregroundId).append('\n'); + myForegroundId = foregroundId; } @Override public void handleFont(int fontNameId) throws Exception { - myBuffer.append("\\f").append(fontNameId); + myBuffer.append("\\f").append(fontNameId).append('\n'); + myFontNameId = fontNameId; } @Override @@ -177,6 +209,7 @@ public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransfera myBuffer.append('0'); } myBuffer.append('\n'); + myFontStyle = style; } } } diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java index 45731a78eb22..b6bb52c992ed 100644 --- a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java +++ b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateManager.java @@ -8,6 +8,7 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.AbstractCollection; @@ -15,11 +16,16 @@ import com.intellij.util.xmlb.annotations.Property; import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; +import javax.crypto.BadPaddingException; +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.LinkedHashSet; import java.util.concurrent.Callable; @@ -109,8 +115,10 @@ public class CertificateManager implements ApplicationComponent, PersistentState try { // Don't do this: protocol created this way will ignore SSL tunnels. See IDEA-115708. // Protocol.registerProtocol("https", CertificateManager.createDefault().createProtocol()); - SSLContext.setDefault(getSslContext()); - LOG.debug("Default SSL context initialized"); + if (Registry.is("ide.certificate.manager")) { + SSLContext.setDefault(getSslContext()); + LOG.debug("Default SSL context initialized"); + } } catch (Exception e) { LOG.error(e); @@ -152,12 +160,21 @@ public class CertificateManager implements ApplicationComponent, PersistentState // SSLContext context = SSLContext.getDefault(); // NOTE: existence of default trust manager can be checked here as // assert systemManager.getAcceptedIssuers().length != 0 - context.init(null, new TrustManager[]{getTrustManager()}, null); + context.init(getDefaultKeyManagers(), new TrustManager[]{getTrustManager()}, null); } - catch (Exception e) { + catch (KeyManagementException e) { LOG.error(e); } } + else { + // IDEA-124057 Do not touch default context at all if certificate manager was disabled. + + // For some reason passing `null` as first parameter of SSLContext#init is not enough to + // use -Djavax.net.ssl.keyStore VM parameters, although -Djavax.net.ssl.trustStore is used + // successfully. See this question on Stackoverflow for details + // http://stackoverflow.com/questions/23205266/java-key-store-is-not-found-when-default-ssl-context-is-redefined + context = getDefaultSslContext(); + } mySslContext = context; } return mySslContext; @@ -179,10 +196,75 @@ public class CertificateManager implements ApplicationComponent, PersistentState } catch (KeyManagementException e) { LOG.error(e); - throw new AssertionError("Cannot initialize default SSL context"); + throw new AssertionError("Cannot initialize system SSL context"); } } + @NotNull + private static SSLContext getDefaultSslContext() { + try { + return SSLContext.getDefault(); + } + catch (NoSuchAlgorithmException e) { + LOG.error("Default SSL context not available. Using system instead."); + return getSystemSslContext(); + } + } + + /** + * Workaround for IDEA-124057. Manually find key store specified via VM options. + * + * @return key managers or {@code null} in case of any error + */ + @Nullable + public static KeyManager[] getDefaultKeyManagers() { + String keyStorePath = System.getProperty("javax.net.ssl.keyStore"); + if (keyStorePath != null) { + LOG.info("Loading custom key store specified with VM options: " + keyStorePath); + try { + KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + KeyStore keyStore; + String keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()); + try { + keyStore = KeyStore.getInstance(keyStoreType); + } + catch (KeyStoreException e) { + if (e.getCause() instanceof NoSuchAlgorithmException) { + LOG.error("Wrong key store type: " + keyStoreType, e); + return null; + } + throw e; + } + String password = System.getProperty("javax.net.ssl.keyStorePassword", ""); + InputStream inputStream = null; + try { + inputStream = new FileInputStream(keyStorePath); + keyStore.load(inputStream, password.toCharArray()); + factory.init(keyStore, password.toCharArray()); + } + catch (FileNotFoundException e) { + LOG.error("Key store file not found: " + keyStorePath); + return null; + } + catch (Exception e) { + if (e.getCause() instanceof BadPaddingException) { + LOG.error("Wrong key store password: " + password, e); + return null; + } + throw e; + } + finally { + StreamUtil.closeStream(inputStream); + } + return factory.getKeyManagers(); + } + catch (Exception e) { + LOG.error(e); + } + } + return null; + } + @NotNull public String getCacertsPath() { return myCacertsPath; diff --git a/platform/platform-tests/testData/editor/richcopy/BlockSelection.rtf b/platform/platform-tests/testData/editor/richcopy/BlockSelection.rtf index 5114746a803e..8c20ff6dbe49 100644 --- a/platform/platform-tests/testData/editor/richcopy/BlockSelection.rtf +++ b/platform/platform-tests/testData/editor/richcopy/BlockSelection.rtf @@ -3,17 +3,22 @@ \s0\box\cbpat2\cb2\fs___PLATFORM_SPECIFIC___ - \cf3\f1\i0\b + \cf3 +\f1 +\i0\b -int \cf1\i0\b0 +int \cf1 +\i0\b0 field; \line \line - \cf3\i0\b + \cf3 +\i0\b -public static void \cf1\i0\b0 +public static void \cf1 +\i0\b0 main(String[] args) \{\par} \ No newline at end of file diff --git a/platform/platform-tests/testData/editor/richcopy/NormalSelection.rtf b/platform/platform-tests/testData/editor/richcopy/NormalSelection.rtf index 09294023c9c0..20fa7f70ab2d 100644 --- a/platform/platform-tests/testData/editor/richcopy/NormalSelection.rtf +++ b/platform/platform-tests/testData/editor/richcopy/NormalSelection.rtf @@ -2,31 +2,42 @@ {\fonttbl{\f1 ___PLATFORM_SPECIFIC___;}} \s0\box\cbpat2\cb2\fs___PLATFORM_SPECIFIC___ -\cf3\f1\i0\b +\cf3 +\f1 +\i0\b -public class \cf1\i0\b0 +public class \cf1 +\i0\b0 Basic \{\line - \cf3\i0\b + \cf3 +\i0\b -int \cf1\i0\b0 +int \cf1 +\i0\b0 field;\line \line - \cf3\i0\b + \cf3 +\i0\b -public static void \cf1\i0\b0 +public static void \cf1 +\i0\b0 main(String[] args) \{\line - System.out.println(\cf4\i0\b + System.out.println(\cf4 +\i0\b "Hello\cf3 + \\t\cf4 -world!"\cf1\i0\b0 + +world!"\cf1 +\i0\b0 );\line diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/Variable.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/Variable.java index 8c21ae3ce8ef..d0062375c833 100755 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/Variable.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/Variable.java @@ -4,9 +4,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.values.Value; -/** - * An object that represents a variable in a call frame - */ public interface Variable { /** * @return whether it is possible to read this variable diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ArrayValue.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ArrayValue.java index 26f67831352f..e582b258ba2d 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ArrayValue.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ArrayValue.java @@ -1,7 +1,8 @@ package org.jetbrains.debugger.values; -import com.intellij.openapi.util.AsyncResult; +import com.intellij.openapi.util.ActionCallback; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.Variable; import java.util.List; @@ -18,6 +19,20 @@ public interface ArrayValue extends Value { */ int getLength(); - @NotNull - AsyncResult> getVariables(); + /** + * Ranges of array elements or elements if less than bucketThreshold + */ + @Nullable + ActionCallback getVariables(int from, int to, int bucketThreshold, @NotNull IndexedVariablesConsumer consumer); + + abstract class IndexedVariablesConsumer { + // null if array is not sparse + public abstract void consumeRanges(@Nullable int[] ranges); + + public abstract void consumeVariables(@NotNull List variables); + + public boolean isObsolete() { + return false; + } + } } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValueBase.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValueBase.java index 81cc39f49366..1ab2d9443cab 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValueBase.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/values/ObjectValueBase.java @@ -37,7 +37,7 @@ public abstract class ObjectValueBase extends this.valueManager = valueManager; } - protected abstract void loadProperties(@NotNull AsyncResult> result); + protected abstract void loadProperties(@NotNull AsyncResult> result); protected final void updateCacheStamp() { cacheStamp = valueManager.getCacheStamp(); diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java new file mode 100644 index 000000000000..41ce0c1fca6e --- /dev/null +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java @@ -0,0 +1,97 @@ +package org.jetbrains.debugger; + +import com.intellij.xdebugger.frame.XCompositeNode; +import com.intellij.xdebugger.frame.XValueChildrenList; +import com.intellij.xdebugger.frame.XValueGroup; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.debugger.values.ArrayValue; + +import java.util.List; + +final class LazyVariablesGroup extends XValueGroup { + public static final ValueGroupFactory GROUP_FACTORY = new ValueGroupFactory() { + @Override + public XValueGroup create(@NotNull ArrayValue value, int start, int end, @NotNull VariableContext context) { + return new LazyVariablesGroup(value, start, end, context); + } + }; + + private final ArrayValue value; + + private final int start; + private final int end; + private final VariableContext context; + + public LazyVariablesGroup(@NotNull ArrayValue value, int start, int end, @NotNull VariableContext context) { + super(String.format("[%,d \u2026 %,d]", start, end)); + + this.value = value; + + this.start = start; + this.end = end; + + this.context = context; + } + + @Override + public void computeChildren(@NotNull XCompositeNode node) { + node.setAlreadySorted(true); + + value.getVariables(start, end, XCompositeNode.MAX_CHILDREN_TO_SHOW, new VariableView.ObsolescentIndexedVariablesConsumer(node) { + @Override + public void consumeRanges(@Nullable int[] ranges) { + if (ranges == null) { + XValueChildrenList groupList = new XValueChildrenList(); + addGroups(value, GROUP_FACTORY, groupList, start, end, XCompositeNode.MAX_CHILDREN_TO_SHOW, context); + node.addChildren(groupList, true); + } + else { + addRanges(value, ranges, node, context, true); + } + } + + @Override + public void consumeVariables(@NotNull List variables) { + node.addChildren(Variables.createVariablesList(variables, context), true); + } + }); + } + + public static void addRanges(@NotNull ArrayValue value, int[] ranges, @NotNull XCompositeNode node, @NotNull VariableContext context, boolean isLast) { + XValueChildrenList groupList = new XValueChildrenList(ranges.length / 2); + for (int i = 0, n = ranges.length; i < n; i += 2) { + groupList.addTopGroup(new LazyVariablesGroup(value, ranges[i], ranges[i + 1], context)); + } + node.addChildren(groupList, isLast); + } + + public static void addGroups(@NotNull T data, + @NotNull ValueGroupFactory groupFactory, + @NotNull XValueChildrenList groupList, + int from, + int limit, + int bucketSize, + @NotNull VariableContext context) { + int to = Math.min(bucketSize, limit); + boolean done = false; + do { + int groupFrom = from; + int groupTo = to; + + from += bucketSize; + to = from + Math.min(bucketSize, limit - from); + + // don't create group for only one member + if (to - from == 1) { + groupTo++; + done = true; + } + groupList.addTopGroup(groupFactory.create(data, groupFrom, groupTo, context)); + if (from >= limit) { + break; + } + } + while (!done); + } +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ValueGroupFactory.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ValueGroupFactory.java new file mode 100644 index 000000000000..8699419218fe --- /dev/null +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/ValueGroupFactory.java @@ -0,0 +1,8 @@ +package org.jetbrains.debugger; + +import com.intellij.xdebugger.frame.XValueGroup; +import org.jetbrains.annotations.NotNull; + +interface ValueGroupFactory { + XValueGroup create(@NotNull T data, int start, int end, @NotNull VariableContext context); +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java index 90737cc44488..d198296d0cea 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java @@ -1,6 +1,7 @@ package org.jetbrains.debugger; import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; @@ -47,7 +48,6 @@ public final class VariableView extends XNamedValue implements VariableContext { private volatile List remainingChildren; private volatile int remainingChildrenOffset; - private volatile int childrenModificationStamp; public VariableView(@NotNull VariableContext context, @NotNull Variable variable) { super(context.getMemberFilter().normalizeMemberName(variable)); @@ -213,44 +213,85 @@ public final class VariableView extends XNamedValue implements VariableContext { } @Override - public void computeChildren(@NotNull XCompositeNode node) { + public void computeChildren(@NotNull final XCompositeNode node) { node.setAlreadySorted(true); - if (!(value instanceof ObjectValue) || ((ObjectValue)value).hasProperties() == ThreeState.NO) { - node.addChildren(XValueChildrenList.EMPTY, true); + List list = remainingChildren; + if (list != null) { + int to = Math.min(remainingChildrenOffset + XCompositeNode.MAX_CHILDREN_TO_SHOW, list.size()); + boolean isLast = to == list.size(); + node.addChildren(Variables.createVariablesList(list, remainingChildrenOffset, to, this), isLast); + if (!isLast) { + node.tooManyChildren(list.size() - to); + remainingChildrenOffset += XCompositeNode.MAX_CHILDREN_TO_SHOW; + } return; } - ObsolescentAsyncResults.consume(((ObjectValue)value).getProperties(), node, new PairConsumer, XCompositeNode>() { + boolean hasNamedProperties = value instanceof ObjectValue && ((ObjectValue)value).hasProperties() != ThreeState.NO; + boolean hasIndexedProperties = value instanceof ArrayValue; + ActionCallback.Chunk chunk = new ActionCallback.Chunk(); + if (hasIndexedProperties) { + chunk.add(computeIndexedProperties((ArrayValue)value, node, !hasNamedProperties)); + } + + if (hasNamedProperties) { + chunk.add(computeNamedProperties((ObjectValue)value, node, !hasIndexedProperties)); + } + + if (hasIndexedProperties == hasNamedProperties) { + chunk.create().doWhenProcessed(new Runnable() { + @Override + public void run() { + if (!node.isObsolete()) { + node.addChildren(XValueChildrenList.EMPTY, true); + } + } + }); + } + } + + public abstract static class ObsolescentIndexedVariablesConsumer extends ArrayValue.IndexedVariablesConsumer { + protected final XCompositeNode node; + + protected ObsolescentIndexedVariablesConsumer(@NotNull XCompositeNode node) { + this.node = node; + } + + @Override + public boolean isObsolete() { + return node.isObsolete(); + } + } + + private ActionCallback computeIndexedProperties(@NotNull final ArrayValue value, @NotNull final XCompositeNode node, final boolean isLastChildren) { + return value.getVariables(0, value.getLength(), XCompositeNode.MAX_CHILDREN_TO_SHOW, new ObsolescentIndexedVariablesConsumer(node) { @Override - public void consume(List variables, XCompositeNode node) { - if (value instanceof ArrayValue) { - // todo arrays could have not only indexes values - return; - } - - if (value.getType() == ValueType.ARRAY) { - computeArrayRanges(variables, node); - return; - } - - int maxPropertiesToShow; - if (value.getType() == ValueType.FUNCTION) { - maxPropertiesToShow = Integer.MAX_VALUE; + public void consumeRanges(@Nullable int[] ranges) { + if (ranges == null) { + XValueChildrenList groupList = new XValueChildrenList(); + LazyVariablesGroup.addGroups(value, LazyVariablesGroup.GROUP_FACTORY, groupList, 0, value.getLength(), XCompositeNode.MAX_CHILDREN_TO_SHOW, VariableView.this); + node.addChildren(groupList, isLastChildren); } else { - maxPropertiesToShow = XCompositeNode.MAX_CHILDREN_TO_SHOW; - List list = remainingChildren; - if (list != null && childrenModificationStamp == ((ObjectValue)value).getCacheStamp()) { - int to = Math.min(remainingChildrenOffset + XCompositeNode.MAX_CHILDREN_TO_SHOW, list.size()); - boolean isLast = to == list.size(); - node.addChildren(Variables.createVariablesList(list, remainingChildrenOffset, to, VariableView.this), isLast); - if (!isLast) { - node.tooManyChildren(list.size() - to); - remainingChildrenOffset += XCompositeNode.MAX_CHILDREN_TO_SHOW; - } - return; - } + LazyVariablesGroup.addRanges(value, ranges, node, VariableView.this, isLastChildren); + } + } + + @Override + public void consumeVariables(@NotNull List variables) { + node.addChildren(Variables.createVariablesList(variables, VariableView.this), isLastChildren); + } + }); + } + + private ActionCallback computeNamedProperties(@NotNull final ObjectValue value, @NotNull XCompositeNode node, final boolean isLastChildren) { + return ObsolescentAsyncResults.consume(value.getProperties(), node, new PairConsumer, XCompositeNode>() { + @Override + public void consume(List variables, XCompositeNode node) { + if (value.getType() == ValueType.ARRAY && !(value instanceof ArrayValue)) { + computeArrayRanges(variables, node); + return; } FunctionValue functionValue = value instanceof FunctionValue ? (FunctionValue)value : null; @@ -258,44 +299,21 @@ public final class VariableView extends XNamedValue implements VariableContext { functionValue = null; } - remainingChildren = Variables.sortFilterAndAddValueList(variables, node, VariableView.this, maxPropertiesToShow, functionValue == null); + remainingChildren = Variables.sortFilterAndAddValueList(variables, node, VariableView.this, XCompositeNode.MAX_CHILDREN_TO_SHOW, functionValue == null); if (remainingChildren != null) { - remainingChildrenOffset = maxPropertiesToShow; - childrenModificationStamp = ((ObjectValue)value).getCacheStamp(); + remainingChildrenOffset = XCompositeNode.MAX_CHILDREN_TO_SHOW; } if (functionValue != null) { // we pass context as variable context instead of this variable value - we cannot watch function scopes variables, so, this variable name doesn't matter - node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), true); + node.addChildren(XValueChildrenList.bottomGroup(new FunctionScopesValueGroup(functionValue, context)), isLastChildren); } } }); - - if (value instanceof ArrayValue) { - ObsolescentAsyncResults.consume(((ArrayValue)value).getVariables(), node, new PairConsumer, XCompositeNode>() { - @Override - public void consume(List variables, XCompositeNode node) { - computeIndexedValuesRanges(variables, node); - } - }); - } - } - - private void computeIndexedValuesRanges(@NotNull List variables, @NotNull XCompositeNode node) { - int totalLength = variables.size(); - int bucketSize = XCompositeNode.MAX_CHILDREN_TO_SHOW; - if (totalLength <= bucketSize) { - node.addChildren(Variables.createVariablesList(variables, this), true); - return; - } - - XValueChildrenList groupList = new XValueChildrenList(); - addGroups(variables, groupList, 0, totalLength, bucketSize); - node.addChildren(groupList, true); } private void computeArrayRanges(@NotNull List properties, @NotNull XCompositeNode node) { - List variables = Variables.filterAndSort(properties, this, false); + final List variables = Variables.filterAndSort(properties, this, false); int count = variables.size(); int bucketSize = XCompositeNode.MAX_CHILDREN_TO_SHOW; if (count <= bucketSize) { @@ -311,7 +329,7 @@ public final class VariableView extends XNamedValue implements VariableContext { XValueChildrenList groupList = new XValueChildrenList(); if (count > 0) { - addGroups(variables, groupList, 0, count, bucketSize); + LazyVariablesGroup.addGroups(variables, VariablesGroup.GROUP_FACTORY, groupList, 0, count, bucketSize, this); } int notGroupedVariablesOffset; @@ -323,7 +341,7 @@ public final class VariableView extends XNamedValue implements VariableContext { } if (notGroupedVariablesOffset > 0) { - addGroups(variables, groupList, count, notGroupedVariablesOffset, bucketSize); + LazyVariablesGroup.addGroups(variables, VariablesGroup.GROUP_FACTORY, groupList, count, notGroupedVariablesOffset, bucketSize, this); } } else { @@ -337,29 +355,6 @@ public final class VariableView extends XNamedValue implements VariableContext { node.addChildren(groupList, true); } - private void addGroups(List variables, XValueChildrenList groupList, int from, int limit, int bucketSize) { - int to = Math.min(bucketSize, limit); - boolean done = false; - do { - int groupFrom = from; - int groupTo = to; - - from += bucketSize; - to = from + Math.min(bucketSize, limit - from); - - // don't create group for only one member - if (to - from == 1) { - groupTo++; - done = true; - } - groupList.addTopGroup(VariablesGroup.createArrayRangeGroup(groupFrom, groupTo, variables, this)); - if (from >= limit) { - break; - } - } - while (!done); - } - @NotNull private Icon getIcon() { return getIcon(value); diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariablesGroup.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariablesGroup.java index 553eeaa3986a..32f9b15288ec 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariablesGroup.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariablesGroup.java @@ -7,21 +7,29 @@ import org.jetbrains.annotations.NotNull; import java.util.List; public class VariablesGroup extends XValueGroup { - private final int from; - private final int to; - private final List variables; - private final VariableContext variableContext; + public static final ValueGroupFactory> GROUP_FACTORY = new ValueGroupFactory>() { + @Override + public XValueGroup create(@NotNull List variables, int start, int end, @NotNull VariableContext context) { + return createArrayRangeGroup(start, end, variables, context); + } + }; - public VariablesGroup(@NotNull String name, @NotNull List variables, VariableContext variableContext) { - this(0, variables.size(), variables, variableContext, name); + private final int start; + private final int end; + private final List variables; + private final VariableContext context; + + public VariablesGroup(@NotNull String name, @NotNull List variables, VariableContext context) { + this(0, variables.size(), variables, context, name); } - private VariablesGroup(int from, int to, @NotNull List variables, @NotNull VariableContext variableContext, final String name) { + private VariablesGroup(int start, int end, @NotNull List variables, @NotNull VariableContext context, @NotNull String name) { super(name); - this.from = from; - this.to = to; + + this.start = start; + this.end = end; this.variables = variables; - this.variableContext = variableContext; + this.context = context; } public static VariablesGroup createArrayRangeGroup(int start, int end, List variables, VariableContext variableContext) { @@ -32,6 +40,6 @@ public class VariablesGroup extends XValueGroup { @Override public void computeChildren(@NotNull XCompositeNode node) { node.setAlreadySorted(true); - node.addChildren(Variables.createVariablesList(variables, from, to, variableContext), true); + node.addChildren(Variables.createVariablesList(variables, start, end, context), true); } } \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java index eac3f7e54b61..7dad7854ca0d 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java @@ -174,6 +174,11 @@ public final class JsonReaderEx implements Closeable { this.lenient = lenient; } + public final JsonReaderEx lenient(boolean lenient) { + this.lenient = lenient; + return this; + } + @SuppressWarnings("UnusedDeclaration") public final boolean isLenient() { return lenient; diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java index 8f57a6d2af01..fa4d40dc2750 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java @@ -1,6 +1,7 @@ package com.intellij.tasks.integration; import com.intellij.tasks.Task; +import com.intellij.tasks.TaskBundle; import com.intellij.tasks.TaskManagerTestCase; import com.intellij.tasks.impl.LocalTaskImpl; import com.intellij.tasks.impl.TaskUtil; @@ -56,6 +57,21 @@ public class RedmineIntegrationTest extends TaskManagerTestCase { assertEquals("prj-1 7 7 Summary contains 'baz'", TaskUtil.getChangeListComment(localTask)); } + /** + * Redmine doesn't send 401 or 403 errors, when issues are downloaded with wrong credentials, so current user information is + * fetched instead. + */ + public void testCredentialsCheck() throws Exception { + myRepository.setPassword("wrong-password"); + try { + myRepository.testConnection(); + fail("testConnection() should fails, when wrong credentials specified"); + } + catch (Exception e) { + assertEquals(TaskBundle.message("failure.login"), e.getMessage()); + } + } + @Override public void setUp() throws Exception { super.setUp();