/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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.google.dart.tools.debug.core.logical; import com.google.dart.tools.core.utilities.general.StringUtilities; import com.google.dart.tools.debug.core.DartDebugCorePlugin; import com.google.dart.tools.debug.core.util.IDartDebugValue; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IIndexedValue; import org.eclipse.debug.core.model.ILogicalStructureTypeDelegate; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.IVariable; import org.eclipse.debug.core.model.IWatchExpressionListener; import org.eclipse.debug.core.model.IWatchExpressionResult; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * This ILogicalStructureTypeDelegate handles displaying Dart types, like maps, in a more logical * view. */ public class MapStructureType implements ILogicalStructureTypeDelegate { private static final Set<String> MAP_TYPES = new HashSet<String>(Arrays.asList( "Map", "HashMap", "_HashMap", "LinkedHashMap", "_LinkedHashMap", "SplayTreeMap")); private static final Set<String> SET_TYPES = new HashSet<String>(Arrays.asList( "Set", "HashSet", "_LinkedHashSet")); private static final String MAP_EXPR = "keys.expand(" + "(key) => [key is String ? '\\'${key}\\'' : '${key}', this[key]]).toList()"; private static final String SET_EXPR = "expand(" + "(key) => [key is String ? '\\'${key}\\'' : '${key}', key]).toList()"; public MapStructureType() { } @Override public IValue getLogicalStructure(IValue value) throws CoreException { IDartDebugValue dartDebugValue = (IDartDebugValue) value; try { String refTypeName = value.getReferenceTypeName(); if (MAP_TYPES.contains(refTypeName)) { return createMap(dartDebugValue, MAP_EXPR, true); } if (SET_TYPES.contains(refTypeName)) { return createMap(dartDebugValue, SET_EXPR, true); } } catch (Throwable t) { DartDebugCorePlugin.logError(t); } return value; } @Override public boolean providesLogicalStructure(IValue value) { if (!(value instanceof IDartDebugValue)) { return false; } try { String refTypeName = value.getReferenceTypeName(); // Map types. if (MAP_TYPES.contains(refTypeName)) { return true; } // Set types. if (SET_TYPES.contains(refTypeName)) { return true; } } catch (Throwable t) { } return false; } private IValue createMap(IDartDebugValue value, String evalExpr, boolean convertToMap) throws DebugException { final CountDownLatch latch = new CountDownLatch(1); final IWatchExpressionResult[] results = new IWatchExpressionResult[1]; value.evaluateExpression(evalExpr, new IWatchExpressionListener() { @Override public void watchEvaluationFinished(IWatchExpressionResult result) { results[0] = result; latch.countDown(); } }); try { latch.await(3000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new DebugException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, "timeout from debug client")); } IWatchExpressionResult exResult = results[0]; if (exResult.getException() != null) { throw exResult.getException(); } IValue val = exResult.getValue(); if (!(val instanceof IDartDebugValue)) { return val; } if (!convertToMap || !(val instanceof IIndexedValue)) { return val; } IIndexedValue resultValue = (IIndexedValue) val; IVariable[] variables = resultValue.getVariables(0, resultValue.getSize()); List<IVariable> vars = new ArrayList<IVariable>(); for (int i = 0; i < variables.length; i += 2) { String keyName = variables[i].getValue().getValueString(); keyName = StringUtilities.stripQuotes(keyName); IValue keyValue = variables[i + 1].getValue(); vars.add(new LogicalDebugVariable(keyName, keyValue)); } return new LogicalDebugValue(value, vars.toArray(new IVariable[vars.size()])); } }