Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-04-24 14:03:05 +04:00
14 changed files with 411 additions and 133 deletions
@@ -0,0 +1,6 @@
public class Test {
<caret>
@SuppressWarnings("unused") void m() {
System.out.println();
}
}
@@ -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;
}
}
}
@@ -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;
@@ -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}
@@ -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
@@ -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
@@ -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<List<Variable>> 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<Variable> variables);
public boolean isObsolete() {
return false;
}
}
}
@@ -37,7 +37,7 @@ public abstract class ObjectValueBase<VALUE_LOADER extends ValueManager> extends
this.valueManager = valueManager;
}
protected abstract void loadProperties(@NotNull AsyncResult<List<? extends Variable>> result);
protected abstract void loadProperties(@NotNull AsyncResult<List<Variable>> result);
protected final void updateCacheStamp() {
cacheStamp = valueManager.getCacheStamp();
@@ -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<ArrayValue> GROUP_FACTORY = new ValueGroupFactory<ArrayValue>() {
@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<Variable> 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 <T> void addGroups(@NotNull T data,
@NotNull ValueGroupFactory<T> 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);
}
}
@@ -0,0 +1,8 @@
package org.jetbrains.debugger;
import com.intellij.xdebugger.frame.XValueGroup;
import org.jetbrains.annotations.NotNull;
interface ValueGroupFactory<T> {
XValueGroup create(@NotNull T data, int start, int end, @NotNull VariableContext context);
}
@@ -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<Variable> 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<Variable> 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<List<Variable>, 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<Variable> 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<Variable> 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<Variable> 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<List<Variable>, XCompositeNode>() {
@Override
public void consume(List<Variable> 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<List<Variable>, XCompositeNode>() {
@Override
public void consume(List<Variable> variables, XCompositeNode node) {
computeIndexedValuesRanges(variables, node);
}
});
}
}
private void computeIndexedValuesRanges(@NotNull List<Variable> 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<? extends Variable> properties, @NotNull XCompositeNode node) {
List<Variable> variables = Variables.filterAndSort(properties, this, false);
final List<Variable> 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<Variable> 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);
@@ -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<Variable> variables;
private final VariableContext variableContext;
public static final ValueGroupFactory<List<Variable>> GROUP_FACTORY = new ValueGroupFactory<List<Variable>>() {
@Override
public XValueGroup create(@NotNull List<Variable> variables, int start, int end, @NotNull VariableContext context) {
return createArrayRangeGroup(start, end, variables, context);
}
};
public VariablesGroup(@NotNull String name, @NotNull List<Variable> variables, VariableContext variableContext) {
this(0, variables.size(), variables, variableContext, name);
private final int start;
private final int end;
private final List<Variable> variables;
private final VariableContext context;
public VariablesGroup(@NotNull String name, @NotNull List<Variable> variables, VariableContext context) {
this(0, variables.size(), variables, context, name);
}
private VariablesGroup(int from, int to, @NotNull List<Variable> variables, @NotNull VariableContext variableContext, final String name) {
private VariablesGroup(int start, int end, @NotNull List<Variable> 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<Variable> 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);
}
}
@@ -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;
@@ -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();