RemoteObjectPropertyModel.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "RemoteObjectPropertyModel.h"
  7. #include "RemoteObject.h"
  8. #include "RemoteProcess.h"
  9. namespace Inspector {
  10. RemoteObjectPropertyModel::RemoteObjectPropertyModel(RemoteObject& object)
  11. : m_object(object)
  12. {
  13. }
  14. int RemoteObjectPropertyModel::row_count(const GUI::ModelIndex& index) const
  15. {
  16. Function<int(const JsonValue&)> do_count = [&](const JsonValue& value) {
  17. if (value.is_array())
  18. return value.as_array().size();
  19. else if (value.is_object())
  20. return value.as_object().size();
  21. return (size_t)0;
  22. };
  23. if (index.is_valid()) {
  24. auto* path = static_cast<const JsonPath*>(index.internal_data());
  25. return do_count(path->resolve(m_object.json));
  26. } else {
  27. return do_count(m_object.json);
  28. }
  29. }
  30. String RemoteObjectPropertyModel::column_name(int column) const
  31. {
  32. switch (column) {
  33. case Column::Name:
  34. return "Name";
  35. case Column::Value:
  36. return "Value";
  37. }
  38. VERIFY_NOT_REACHED();
  39. }
  40. GUI::Variant RemoteObjectPropertyModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
  41. {
  42. auto* path = static_cast<const JsonPath*>(index.internal_data());
  43. if (!path)
  44. return {};
  45. if (role == GUI::ModelRole::Display) {
  46. switch (index.column()) {
  47. case Column::Name:
  48. return path->last().to_string();
  49. case Column::Value: {
  50. auto data = path->resolve(m_object.json);
  51. if (data.is_array())
  52. return String::formatted("<Array with {} element{}", data.as_array().size(), data.as_array().size() == 1 ? ">" : "s>");
  53. if (data.is_object())
  54. return String::formatted("<Object with {} entr{}", data.as_object().size(), data.as_object().size() == 1 ? "y>" : "ies>");
  55. return data;
  56. }
  57. }
  58. }
  59. return {};
  60. }
  61. void RemoteObjectPropertyModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& new_value)
  62. {
  63. if (!index.is_valid())
  64. return;
  65. auto* path = static_cast<const JsonPath*>(index.internal_data());
  66. if (path->size() != 1)
  67. return;
  68. FlatPtr address = m_object.address;
  69. RemoteProcess::the().set_property(address, path->first().to_string(), new_value.to_string());
  70. did_update();
  71. }
  72. GUI::ModelIndex RemoteObjectPropertyModel::index(int row, int column, const GUI::ModelIndex& parent) const
  73. {
  74. const auto& parent_path = parent.is_valid() ? *static_cast<const JsonPath*>(parent.internal_data()) : JsonPath {};
  75. auto nth_child = [&](int n, const JsonValue& value) -> const JsonPath* {
  76. auto path = make<JsonPath>();
  77. path->extend(parent_path);
  78. int row_index = n;
  79. if (value.is_object()) {
  80. String property_name;
  81. auto& object = value.as_object();
  82. object.for_each_member([&](auto& name, auto&) {
  83. if (row_index > 0) {
  84. --row_index;
  85. } else if (row_index == 0) {
  86. property_name = name;
  87. --row_index;
  88. }
  89. });
  90. if (property_name.is_null())
  91. return nullptr;
  92. path->append({ property_name });
  93. m_paths.append(move(path));
  94. } else if (value.is_array()) {
  95. path->append(JsonPathElement { (size_t)n });
  96. m_paths.append(move(path));
  97. } else {
  98. return nullptr;
  99. }
  100. return &m_paths.last();
  101. };
  102. if (!parent.is_valid()) {
  103. if (m_object.json.is_empty())
  104. return {};
  105. }
  106. auto index_path = cached_path_at(row, parent_path);
  107. if (!index_path)
  108. index_path = nth_child(row, parent_path.resolve(m_object.json));
  109. if (!index_path)
  110. return {};
  111. return create_index(row, column, index_path);
  112. }
  113. GUI::ModelIndex RemoteObjectPropertyModel::parent_index(const GUI::ModelIndex& index) const
  114. {
  115. if (!index.is_valid())
  116. return index;
  117. auto path = *static_cast<const JsonPath*>(index.internal_data());
  118. if (path.is_empty())
  119. return {};
  120. path.take_last();
  121. if (path.is_empty())
  122. return {};
  123. auto* cpath = find_cached_path(path);
  124. if (cpath) {
  125. int index_in_parent = 0;
  126. if (cpath->last().kind() == JsonPathElement::Kind::Index)
  127. index_in_parent = cpath->last().index();
  128. else if (cpath->last().kind() == JsonPathElement::Kind::Key) {
  129. auto path_copy = path;
  130. auto last = path_copy.take_last();
  131. bool found = false;
  132. path_copy.resolve(m_object.json).as_object().for_each_member([&](auto& name, auto&) {
  133. if (!found) {
  134. if (last.key() == name)
  135. found = true;
  136. else
  137. index_in_parent++;
  138. }
  139. });
  140. }
  141. return create_index(index_in_parent, 0, cpath);
  142. }
  143. dbgln("No cached path found for path {}", path.to_string());
  144. return {};
  145. }
  146. const JsonPath* RemoteObjectPropertyModel::cached_path_at(int n, const Vector<JsonPathElement>& prefix) const
  147. {
  148. // FIXME: ModelIndex wants a void*, so we have to keep these
  149. // indices alive, but allocating a new path every time
  150. // we're asked for an index is silly, so we have to look for existing ones first.
  151. const JsonPath* index_path = nullptr;
  152. int row_index = n;
  153. for (auto& path : m_paths) {
  154. if (path.size() != prefix.size() + 1)
  155. continue;
  156. for (size_t i = 0; i < prefix.size(); ++i) {
  157. if (path[i] != prefix[i])
  158. goto do_continue;
  159. }
  160. if (row_index == 0) {
  161. index_path = &path;
  162. break;
  163. }
  164. --row_index;
  165. do_continue:;
  166. }
  167. return index_path;
  168. };
  169. const JsonPath* RemoteObjectPropertyModel::find_cached_path(const Vector<JsonPathElement>& path) const
  170. {
  171. for (auto& cpath : m_paths) {
  172. if (cpath.size() != path.size())
  173. continue;
  174. for (size_t i = 0; i < cpath.size(); ++i) {
  175. if (cpath[i] != path[i])
  176. goto do_continue;
  177. }
  178. return &cpath;
  179. do_continue:;
  180. }
  181. return nullptr;
  182. }
  183. }