您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
1046 行
22 KiB
1046 行
22 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using NUnit.Framework;
|
|
using Unity.UIWidgets.async2;
|
|
using Unity.UIWidgets.DevTools;
|
|
using Unity.UIWidgets.DevTools.ui;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
|
|
namespace Unity.UIWidgets.DevTools.inspector
|
|
{
|
|
|
|
public class DiagnosticsNodeUtils
|
|
{
|
|
EnumUtils<DiagnosticLevel> diagnosticLevelUtils =
|
|
new EnumUtils<DiagnosticLevel>(Enum.GetValues(typeof(DiagnosticLevel)).Cast<DiagnosticLevel>().ToList());
|
|
|
|
EnumUtils<DiagnosticsTreeStyle> treeStyleUtils =
|
|
new EnumUtils<DiagnosticsTreeStyle>(Enum.GetValues(typeof(DiagnosticsTreeStyle)).Cast<DiagnosticsTreeStyle>().ToList());
|
|
}
|
|
|
|
public class RemoteDiagnosticsNode : DiagnosticableTree {
|
|
public RemoteDiagnosticsNode(
|
|
Dictionary<string, object> json,
|
|
Future<ObjectGroup> inspectorService,
|
|
bool isProperty,
|
|
RemoteDiagnosticsNode parent
|
|
)
|
|
{
|
|
this.json = json;
|
|
this.inspectorService = inspectorService;
|
|
this.isProperty = isProperty;
|
|
this.parent = parent;
|
|
}
|
|
|
|
public static readonly CustomIconMaker iconMaker = new CustomIconMaker();
|
|
|
|
public static BoxConstraints deserializeConstraints(Dictionary<string, object> json) {
|
|
if (json == null) return null;
|
|
return new BoxConstraints(
|
|
minWidth: float.Parse((string)json["minWidth"] ?? "0.0f"),
|
|
maxWidth: float.Parse((string)json["maxWidth"] ?? "Infinity"),
|
|
minHeight: float.Parse((string)json["minHeight"] ?? "0.0f"),
|
|
maxHeight: float.Parse((string)json["maxHeight"] ?? "Infinity")
|
|
);
|
|
}
|
|
|
|
static BoxParentData deserializeParentData(Dictionary<string, object> json) {
|
|
if (json == null) return null;
|
|
BoxParentData boxParentData = new BoxParentData();
|
|
boxParentData.offset = new Offset(
|
|
float.Parse((string)json["offsetX"] ?? "0.0f"),
|
|
float.Parse((string)json["offsetY"] ?? "0.0f")
|
|
);
|
|
return boxParentData;
|
|
|
|
}
|
|
|
|
static Size deserializeSize(Dictionary<string, object> json) {
|
|
if (json == null) return null;
|
|
return new Size(
|
|
float.Parse((string)json["width"]),
|
|
float.Parse((string)json["height"])
|
|
);
|
|
}
|
|
|
|
static FlexFit? deserializeFlexFit(String flexFit) {
|
|
if (flexFit == null) {
|
|
return null;
|
|
} else if (flexFit == "tight") return FlexFit.tight;
|
|
return FlexFit.loose;
|
|
}
|
|
|
|
/// This node's parent (if it's been set).
|
|
public RemoteDiagnosticsNode parent;
|
|
|
|
Future<string> propertyDocFuture;
|
|
|
|
List<RemoteDiagnosticsNode> cachedProperties;
|
|
|
|
/// Service used to retrieve more detailed information about the value of
|
|
/// the property and its children and properties.
|
|
public readonly Future<ObjectGroup> inspectorService;
|
|
|
|
/// JSON describing the diagnostic node.
|
|
public readonly Dictionary<string, object> json;
|
|
|
|
Future<Dictionary<string, InstanceRef>> _valueProperties;
|
|
|
|
public readonly bool isProperty;
|
|
|
|
private List<string> Flex = new List<string> {"Row", "Column", "Flex"};
|
|
// TODO(albertusangga): Refactor to cleaner/more robust solution
|
|
public bool isFlex
|
|
{
|
|
get
|
|
{
|
|
return Flex.Contains(widgetRuntimeType);
|
|
}
|
|
}
|
|
|
|
|
|
bool isBox
|
|
{
|
|
get
|
|
{
|
|
return (bool)json.getOrDefault("isBox");
|
|
}
|
|
}
|
|
|
|
public float flexFactor
|
|
{
|
|
get
|
|
{
|
|
return (float)json.getOrDefault("flexFactor");
|
|
}
|
|
}
|
|
|
|
public FlexFit? flexFit
|
|
{
|
|
get
|
|
{
|
|
return deserializeFlexFit((string)json["flexFit"]);
|
|
}
|
|
}
|
|
|
|
public RemoteDiagnosticsNode renderObject {
|
|
get
|
|
{
|
|
if (_renderObject != null) return _renderObject;
|
|
Dictionary<string, object> data = (Dictionary<string, object>)json["renderObject"];
|
|
if (data == null) return null;
|
|
_renderObject = new RemoteDiagnosticsNode(data, inspectorService, false, null);
|
|
return _renderObject;
|
|
}
|
|
|
|
}
|
|
|
|
RemoteDiagnosticsNode _renderObject;
|
|
|
|
public RemoteDiagnosticsNode parentRenderElement {
|
|
get
|
|
{
|
|
var data = json["parentRenderElement"];
|
|
if (data == null) return null;
|
|
_parentRenderElement =
|
|
DevTools.RemoteDiagnosticsNode(data, inspectorService, false, null);
|
|
return _parentRenderElement;
|
|
}
|
|
|
|
}
|
|
|
|
RemoteDiagnosticsNode _parentRenderElement;
|
|
|
|
public BoxConstraints constraints
|
|
{
|
|
get
|
|
{
|
|
return deserializeConstraints((Dictionary<string, object>)json["constraints"]);
|
|
}
|
|
}
|
|
|
|
public BoxParentData parentData
|
|
{
|
|
get
|
|
{
|
|
return deserializeParentData((Dictionary<string, object>)json["parentData"]);
|
|
}
|
|
}
|
|
|
|
public Size size
|
|
{
|
|
get
|
|
{
|
|
return deserializeSize((Dictionary<string, object>)json["size"]);
|
|
}
|
|
}
|
|
|
|
//TODO return type may has error
|
|
bool? isLocalClass {
|
|
get
|
|
{
|
|
var objectGroup = inspectorService;
|
|
if (objectGroup is ObjectGroup) {
|
|
return _isLocalClass = _isLocalClass?? objectGroup.inspectorService.isLocalClass(this);
|
|
} else {
|
|
// TODO(jacobr): if objectGroup is a Future<ObjectGroup> we cannot compute
|
|
// whether classes are local as for convenience we need this method to
|
|
// return synchronously.
|
|
return _isLocalClass = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
bool? _isLocalClass;
|
|
|
|
|
|
public override bool operator ==(dynamic other) {
|
|
if (!(other is RemoteDiagnosticsNode)) return false;
|
|
return dartDiagnosticRef == other.dartDiagnosticRef;
|
|
|
|
public override int hashCode
|
|
{
|
|
get
|
|
{
|
|
return dartDiagnosticRef.hashCode;
|
|
}
|
|
}
|
|
|
|
public string separator
|
|
{
|
|
get
|
|
{
|
|
return showSeparator ? ":" : "";
|
|
}
|
|
}
|
|
|
|
public string name
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("name");
|
|
}
|
|
}
|
|
|
|
public bool showSeparator
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("showSeparator", true);
|
|
}
|
|
}
|
|
|
|
public string description
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("description");
|
|
}
|
|
}
|
|
|
|
public DiagnosticLevel level
|
|
{
|
|
get
|
|
{
|
|
return getLevelMember("level", DiagnosticLevel.info);
|
|
}
|
|
}
|
|
|
|
public bool showName
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("showName", true);
|
|
}
|
|
}
|
|
|
|
string getEmptyBodyDescription()
|
|
{
|
|
return getStringMember("emptyBodyDescription");
|
|
}
|
|
|
|
/// Hint for how the node should be displayed.
|
|
public DiagnosticsTreeStyle? style {
|
|
get
|
|
{
|
|
return _style = _style?? getStyleMember("style", DiagnosticsTreeStyle.sparse);
|
|
}
|
|
set
|
|
{
|
|
_style = value;
|
|
}
|
|
}
|
|
|
|
DiagnosticsTreeStyle? _style;
|
|
|
|
|
|
public string type
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("type");
|
|
}
|
|
}
|
|
|
|
bool isQuoted
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("quoted", false);
|
|
}
|
|
}
|
|
|
|
bool hasIsQuoted
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("quoted");
|
|
}
|
|
}
|
|
|
|
/// Optional unit the [value] is measured in.
|
|
///
|
|
/// Unit must be acceptable to display immediately after a number with no
|
|
/// spaces. For example: 'physical pixels per logical pixel' should be a
|
|
/// [tooltip] not a [unit].
|
|
///
|
|
/// Only specified for Number properties.
|
|
string unit
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("unit");
|
|
}
|
|
}
|
|
|
|
bool hasUnit
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("unit");
|
|
}
|
|
}
|
|
|
|
string numberToString
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("numberToString");
|
|
}
|
|
}
|
|
|
|
bool hasNumberToString
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("numberToString");
|
|
}
|
|
}
|
|
|
|
string ifTrue
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("ifTrue");
|
|
}
|
|
}
|
|
|
|
bool hasIfTrue
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("ifTrue");
|
|
}
|
|
}
|
|
|
|
string ifFalse
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("ifFalse");
|
|
}
|
|
}
|
|
|
|
bool hasIfFalse
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("ifFalse");
|
|
}
|
|
}
|
|
|
|
|
|
//[!!!] may has error
|
|
List<string> values {
|
|
get
|
|
{
|
|
var rawValues = json["values"];
|
|
if (rawValues == null) {
|
|
return null;
|
|
}
|
|
return rawValues.ToList();
|
|
}
|
|
|
|
}
|
|
|
|
bool hasValues
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("values");
|
|
}
|
|
}
|
|
|
|
/// Description to use if the property [value] is not null.
|
|
///
|
|
/// If the property [value] is not null and [ifPresent] is null, the
|
|
/// [level] for the property is [DiagnosticsLevel.hidden] and the description
|
|
/// from superclass is used.
|
|
///
|
|
/// Only specified for ObjectFlagProperty.
|
|
string ifPresent
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("ifPresent");
|
|
}
|
|
}
|
|
|
|
bool hasIfPresent
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("ifPresent");
|
|
}
|
|
}
|
|
|
|
string defaultValue
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("defaultValue");
|
|
}
|
|
}
|
|
|
|
public bool hasDefaultValue
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("defaultValue");
|
|
}
|
|
}
|
|
|
|
|
|
string ifEmpty
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("ifEmpty");
|
|
}
|
|
}
|
|
|
|
string ifNull
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("ifNull");
|
|
}
|
|
}
|
|
|
|
bool allowWrap
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("allowWrap", true);
|
|
}
|
|
}
|
|
|
|
string tooltip
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("tooltip") ?? "";
|
|
}
|
|
}
|
|
|
|
bool hasTooltip
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("tooltip");
|
|
}
|
|
}
|
|
|
|
bool missingIfNull
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("missingIfNull", false);
|
|
}
|
|
}
|
|
|
|
string exception
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("exception");
|
|
}
|
|
}
|
|
|
|
/// Whether accessing the property throws an exception.
|
|
bool hasException
|
|
{
|
|
get
|
|
{
|
|
return json.ContainsKey("exception");
|
|
}
|
|
}
|
|
|
|
bool hasCreationLocation {
|
|
get
|
|
{
|
|
return _creationLocation != null || json.ContainsKey("creationLocation");
|
|
}
|
|
|
|
}
|
|
|
|
int locationId
|
|
{
|
|
get
|
|
{
|
|
return JsonUtils.getIntMember(json, "locationId");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InspectorSourceLocation _creationLocation;
|
|
|
|
InspectorSourceLocation creationLocation {
|
|
get
|
|
{
|
|
if (_creationLocation != null) {
|
|
return _creationLocation;
|
|
}
|
|
if (!hasCreationLocation) {
|
|
return null;
|
|
}
|
|
_creationLocation = new InspectorSourceLocation(json["creationLocation"], null);
|
|
return _creationLocation;
|
|
}
|
|
set {
|
|
_creationLocation = value;
|
|
}
|
|
|
|
}
|
|
|
|
public string propertyType
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("propertyType");
|
|
}
|
|
}
|
|
|
|
DiagnosticLevel defaultLevel {
|
|
get
|
|
{
|
|
return getLevelMember("defaultLevel", DiagnosticLevel.info);
|
|
}
|
|
|
|
}
|
|
|
|
/// TODO(jacobr): add helpers to get the properties and children of
|
|
/// this diagnosticable value even if getChildren and getProperties
|
|
/// would return null. This will allow showing nested data for properties
|
|
/// that don't show children by default in other debugging output but
|
|
/// could.
|
|
public bool isDiagnosticableValue {
|
|
get
|
|
{
|
|
return getBooleanMember("isDiagnosticableValue", false);
|
|
}
|
|
|
|
}
|
|
|
|
string getStringMember(string memberName) {
|
|
return JsonUtils.getStringMember(json, memberName);
|
|
}
|
|
|
|
bool getBooleanMember(string memberName, bool defaultValue) {
|
|
if (json[memberName] == null) {
|
|
return defaultValue;
|
|
}
|
|
return json[memberName];
|
|
}
|
|
|
|
DiagnosticLevel getLevelMember(
|
|
string memberName, DiagnosticLevel defaultValue) {
|
|
string value = json[memberName];
|
|
if (value == null) {
|
|
return defaultValue;
|
|
}
|
|
var level = diagnosticLevelUtils.enumEntry(value);
|
|
D.assert(level != null, () => "Unabled to find level for $value");
|
|
return level ?? defaultValue;
|
|
}
|
|
|
|
DiagnosticsTreeStyle getStyleMember(
|
|
string memberName, DiagnosticsTreeStyle defaultValue) {
|
|
if (!json.ContainsKey(memberName)) {
|
|
return defaultValue;
|
|
}
|
|
string value = json[memberName];
|
|
if (value == null) {
|
|
return defaultValue;
|
|
}
|
|
var style = treeStyleUtils.enumEntry(value);
|
|
D.assert(style != null);
|
|
return style ?? defaultValue;
|
|
}
|
|
|
|
public InspectorInstanceRef valueRef
|
|
{
|
|
get
|
|
{
|
|
return InspectorInstanceRef(json["valueId"]);
|
|
}
|
|
}
|
|
|
|
bool isEnumProperty() {
|
|
return type != null && type.StartsWith("EnumProperty<");
|
|
}
|
|
|
|
Future<Dictionary<string, InstanceRef>> valueProperties {
|
|
get
|
|
{
|
|
if (_valueProperties == null)
|
|
{
|
|
if (propertyType == null || valueRef?.id == null)
|
|
{
|
|
_valueProperties = Future.value().to<Dictionary<string, InstanceRef>>();
|
|
return _valueProperties;
|
|
}
|
|
|
|
if (isEnumProperty())
|
|
{
|
|
return (await inspectorService)?.getEnumPropertyValues(valueRef);
|
|
}
|
|
|
|
List<string> propertyNames;
|
|
|
|
switch (propertyType)
|
|
{
|
|
case "Color":
|
|
propertyNames = new List<string> {"red", "green", "blue", "alpha"};
|
|
break;
|
|
case "IconData":
|
|
propertyNames = new List<string> {"codePoint"};
|
|
break;
|
|
default:
|
|
_valueProperties = Future.value().to<Dictionary<string, InstanceRef>>();
|
|
return _valueProperties;
|
|
}
|
|
|
|
_valueProperties = (await inspectorService)
|
|
?.getDartObjectProperties(valueRef, propertyNames);
|
|
}
|
|
|
|
return _valueProperties;
|
|
}
|
|
}
|
|
|
|
public Dictionary<string, object> valuePropertiesJson
|
|
{
|
|
get
|
|
{
|
|
return json["valueProperties"];
|
|
}
|
|
}
|
|
|
|
public bool hasChildren {
|
|
get
|
|
{
|
|
List<object> children = (List<object>)json["children"];
|
|
if (children != null) {
|
|
return children.isNotEmpty();
|
|
}
|
|
return getBooleanMember("hasChildren", false);
|
|
}
|
|
|
|
}
|
|
|
|
public bool isCreatedByLocalProject {
|
|
get
|
|
{
|
|
return getBooleanMember("createdByLocalProject", false);
|
|
}
|
|
|
|
}
|
|
|
|
/// Whether this node is being displayed as a full tree or a filtered tree.
|
|
public bool isSummaryTree
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("summaryTree", false);
|
|
}
|
|
}
|
|
|
|
/// Whether this node is being displayed as a full tree or a filtered tree.
|
|
bool isStateful
|
|
{
|
|
get
|
|
{
|
|
return getBooleanMember("stateful", false);
|
|
}
|
|
}
|
|
|
|
string widgetRuntimeType
|
|
{
|
|
get
|
|
{
|
|
return getStringMember("widgetRuntimeType");
|
|
}
|
|
}
|
|
|
|
public bool childrenReady {
|
|
get
|
|
{
|
|
return json.ContainsKey("children") || _children != null || !hasChildren;
|
|
}
|
|
|
|
}
|
|
|
|
public Future<List<RemoteDiagnosticsNode>> children {
|
|
get
|
|
{
|
|
_computeChildren().then(() =>
|
|
{
|
|
if (_children != null) return _children;
|
|
return _childrenFuture;
|
|
});
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
public List<RemoteDiagnosticsNode> childrenNow {
|
|
get
|
|
{
|
|
_maybePopulateChildren();
|
|
return _children;
|
|
}
|
|
|
|
}
|
|
|
|
Future _computeChildren() {
|
|
_maybePopulateChildren();
|
|
if (!hasChildren || _children != null) {
|
|
return null;
|
|
}
|
|
|
|
if (_childrenFuture != null){
|
|
return _childrenFuture;
|
|
}
|
|
|
|
_childrenFuture = _getChildrenHelper();
|
|
try
|
|
{
|
|
_childrenFuture.then((_children) => { _children = _children ?? new List<RemoteDiagnosticsNode>(); });
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
D.assert(false,()=>"Future _computeChildren() has an unknown exception");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Future<List<RemoteDiagnosticsNode>> _getChildrenHelper() {
|
|
return (await inspectorService)?.getChildren(
|
|
dartDiagnosticRef,
|
|
isSummaryTree,
|
|
this
|
|
);
|
|
}
|
|
|
|
void _maybePopulateChildren() {
|
|
if (!hasChildren || _children != null) {
|
|
return;
|
|
}
|
|
|
|
List<object> jsonArray = json["children"];
|
|
if (jsonArray?.isNotEmpty() == true) {
|
|
List<RemoteDiagnosticsNode> nodes = new List<RemoteDiagnosticsNode>();
|
|
foreach (var element in jsonArray)
|
|
{
|
|
var child =
|
|
new RemoteDiagnosticsNode(element, inspectorService, false, parent);
|
|
child.parent = this;
|
|
nodes.Add(child);
|
|
}
|
|
_children = nodes;
|
|
}
|
|
}
|
|
|
|
Future<List<RemoteDiagnosticsNode>> _childrenFuture;
|
|
List<RemoteDiagnosticsNode> _children;
|
|
|
|
/// Reference the actual Dart DiagnosticsNode object this object is referencing.
|
|
public InspectorInstanceRef dartDiagnosticRef {
|
|
get
|
|
{
|
|
return new InspectornstanceRef(json["objectId"]);
|
|
}
|
|
|
|
}
|
|
|
|
/// Properties to show inline in the widget tree.
|
|
public List<RemoteDiagnosticsNode> inlineProperties {
|
|
get
|
|
{
|
|
if (cachedProperties == null) {
|
|
cachedProperties = new List<RemoteDiagnosticsNode>();
|
|
if (json.ContainsKey("properties")) {
|
|
List<object> jsonArray = json["properties"];
|
|
foreach (Dictionary<string, object> element in jsonArray) {
|
|
cachedProperties.Add(
|
|
new RemoteDiagnosticsNode(element, inspectorService, true, parent));
|
|
}
|
|
trackPropertiesMatchingParameters(cachedProperties);
|
|
}
|
|
}
|
|
return cachedProperties;
|
|
}
|
|
|
|
}
|
|
|
|
Future<List<RemoteDiagnosticsNode>> getProperties(ObjectGroup objectGroup)
|
|
{
|
|
return objectGroup.getProperties(dartDiagnosticRef).then((v) => { trackPropertiesMatchingParameters(v);});
|
|
}
|
|
|
|
List<RemoteDiagnosticsNode> trackPropertiesMatchingParameters(
|
|
List<RemoteDiagnosticsNode> nodes) {
|
|
List<InspectorSourceLocation> parameterLocations =
|
|
creationLocation?.getParameterLocations();
|
|
if (parameterLocations != null) {
|
|
Dictionary<String, InspectorSourceLocation> names = new Dictionary<string, InspectorSourceLocation>();
|
|
foreach (InspectorSourceLocation location in parameterLocations) {
|
|
string name = location.getName();
|
|
if (name != null) {
|
|
names[name] = location;
|
|
}
|
|
}
|
|
foreach (RemoteDiagnosticsNode node in nodes) {
|
|
node.parent = this;
|
|
string name = node.name;
|
|
if (name != null) {
|
|
InspectorSourceLocation parameterLocation = names[name];
|
|
if (parameterLocation != null) {
|
|
node.creationLocation = parameterLocation;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nodes;
|
|
}
|
|
|
|
Future<string> propertyDoc {
|
|
get
|
|
{
|
|
propertyDocFuture = propertyDocFuture ?? _createPropertyDocFuture();
|
|
return propertyDocFuture;
|
|
}
|
|
|
|
}
|
|
|
|
Future<string> _createPropertyDocFuture() {
|
|
// TODO(jacobr): We need access to the analyzer to support this feature.
|
|
/*
|
|
if (parent != null) {
|
|
DartVmServiceValue vmValue = inspectorService.toDartVmServiceValueForSourceLocation(parent.getValueRef());
|
|
if (vmValue == null) {
|
|
return null;
|
|
}
|
|
return inspectorService.getPropertyLocation(vmValue.getInstanceRef(), getName())
|
|
.thenApplyAsync((XSourcePosition sourcePosition) -> {
|
|
if (sourcePosition != null) {
|
|
final VirtualFile file = sourcePosition.getFile();
|
|
final int offset = sourcePosition.getOffset();
|
|
|
|
final Project project = getProject(file);
|
|
if (project != null) {
|
|
final List<HoverInformation> hovers =
|
|
DartAnalysisServerService.getInstance(project).analysis_getHover(file, offset);
|
|
if (!hovers.isEmpty()) {
|
|
return hovers.get(0).getDartdoc();
|
|
}
|
|
}
|
|
}
|
|
return 'Unable to find property source';
|
|
});
|
|
});
|
|
}
|
|
*/
|
|
return Future.value("Unable to find property source").to<string>();
|
|
}
|
|
|
|
public Widget icon {
|
|
get
|
|
{
|
|
if (isProperty) return null;
|
|
return iconMaker.fromWidgetName(widgetRuntimeType);
|
|
}
|
|
}
|
|
|
|
bool identicalDisplay(RemoteDiagnosticsNode node) {
|
|
if (node == null) {
|
|
return false;
|
|
}
|
|
var entries = json.entries;
|
|
if (entries.length != node.json.entries.length) {
|
|
return false;
|
|
}
|
|
foreach (var entry in entries) {
|
|
string key = entry.key;
|
|
if (key == "objectId" || key == "valueId") {
|
|
continue;
|
|
}
|
|
if (entry.value == node.json[key]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
foreach (var property in inlineProperties) {
|
|
properties.add(new DiagnosticsProperty<RemoteDiagnosticsNode>(property.name, property));
|
|
}
|
|
}
|
|
|
|
|
|
public override List<DiagnosticsNode> debugDescribeChildren() {
|
|
var children = childrenNow;
|
|
if (children == null || children.isEmpty()) return new List<DiagnosticsNode>();
|
|
var regularChildren = new List<DiagnosticsNode>();
|
|
foreach (var child in children) {
|
|
regularChildren.Add(child.toDiagnosticsNode());
|
|
}
|
|
return regularChildren;
|
|
}
|
|
|
|
|
|
public override DiagnosticsNode toDiagnosticsNode(string name = null, DiagnosticsTreeStyle style = DiagnosticsTreeStyle.none) {
|
|
return base.toDiagnosticsNode(
|
|
name: name ?? this.name,
|
|
style: DiagnosticsTreeStyle.sparse
|
|
);
|
|
}
|
|
|
|
|
|
public override string toStringShort() {
|
|
return description;
|
|
}
|
|
|
|
public Future setSelectionInspector(bool uiAlreadyUpdated) {
|
|
await (await inspectorService)
|
|
?.setSelectionInspector(valueRef, uiAlreadyUpdated);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class InspectorSourceLocation {
|
|
public InspectorSourceLocation(Dictionary<string, object> json, InspectorSourceLocation parent)
|
|
{
|
|
this.json = json;
|
|
this.parent = parent;
|
|
}
|
|
|
|
public readonly Dictionary<string, object> json;
|
|
public readonly InspectorSourceLocation parent;
|
|
|
|
string path
|
|
{
|
|
get
|
|
{
|
|
return JsonUtils.getStringMember(json, "file");
|
|
}
|
|
}
|
|
|
|
string getFile() {
|
|
var fileName = path;
|
|
if (fileName == null) {
|
|
return parent != null ? parent.getFile() : null;
|
|
}
|
|
|
|
return fileName;
|
|
}
|
|
|
|
int getLine()
|
|
{
|
|
|
|
return JsonUtils.getIntMember(json, "line");
|
|
}
|
|
|
|
public string getName()
|
|
{
|
|
|
|
return JsonUtils.getStringMember(json, "name");
|
|
}
|
|
|
|
int getColumn()
|
|
{
|
|
|
|
return JsonUtils.getIntMember(json, "column");
|
|
}
|
|
|
|
SourcePosition getXSourcePosition() {
|
|
var file = getFile();
|
|
if (file == null) {
|
|
return null;
|
|
}
|
|
int line = getLine();
|
|
int column = getColumn();
|
|
if (line < 0 || column < 0) {
|
|
return null;
|
|
}
|
|
return new SourcePosition(file: file, line: line - 1, column: column - 1);
|
|
}
|
|
|
|
public List<InspectorSourceLocation> getParameterLocations() {
|
|
if (json.ContainsKey("parameterLocations")) {
|
|
List<object> parametersJson = json["parameterLocations"];
|
|
List<InspectorSourceLocation> ret = new List<InspectorSourceLocation>();
|
|
for (int i = 0; i < parametersJson.Count; ++i) {
|
|
ret.Add(new InspectorSourceLocation(parametersJson[i], this));
|
|
}
|
|
return ret;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class SourcePosition {
|
|
public SourcePosition(string file, int line, int column)
|
|
{
|
|
this.file = file;
|
|
this.line = line;
|
|
this.column = column;
|
|
}
|
|
|
|
public readonly string file;
|
|
public readonly int line;
|
|
public readonly int column;
|
|
}
|
|
}
|