DOMTreeModel.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #include "DOMTreeModel.h"
  2. #include <AK/StringBuilder.h>
  3. #include <LibHTML/DOM/Document.h>
  4. #include <LibHTML/DOM/Text.h>
  5. #include <ctype.h>
  6. #include <stdio.h>
  7. DOMTreeModel::DOMTreeModel(Document& document)
  8. : m_document(document)
  9. {
  10. m_element_icon.set_bitmap_for_size(16, GraphicsBitmap::load_from_file("/res/icons/16x16/inspector-object.png"));
  11. m_text_icon.set_bitmap_for_size(16, GraphicsBitmap::load_from_file("/res/icons/16x16/filetype-unknown.png"));
  12. }
  13. DOMTreeModel::~DOMTreeModel()
  14. {
  15. }
  16. GModelIndex DOMTreeModel::index(int row, int column, const GModelIndex& parent) const
  17. {
  18. if (!parent.is_valid()) {
  19. return create_index(row, column, &m_document);
  20. }
  21. auto& parent_node = *static_cast<Node*>(parent.internal_data());
  22. return create_index(row, column, parent_node.child_at_index(row));
  23. }
  24. GModelIndex DOMTreeModel::parent_index(const GModelIndex& index) const
  25. {
  26. if (!index.is_valid())
  27. return {};
  28. auto& node = *static_cast<Node*>(index.internal_data());
  29. if (!node.parent())
  30. return {};
  31. // No grandparent? Parent is the document!
  32. if (!node.parent()->parent()) {
  33. return create_index(0, 0, &m_document);
  34. }
  35. // Walk the grandparent's children to find the index of node's parent in its parent.
  36. // (This is needed to produce the row number of the GModelIndex corresponding to node's parent.)
  37. int grandparent_child_index = 0;
  38. for (auto* grandparent_child = node.parent()->parent()->first_child(); grandparent_child; grandparent_child = grandparent_child->next_sibling()) {
  39. if (grandparent_child == node.parent())
  40. return create_index(grandparent_child_index, 0, node.parent());
  41. ++grandparent_child_index;
  42. }
  43. ASSERT_NOT_REACHED();
  44. return {};
  45. }
  46. int DOMTreeModel::row_count(const GModelIndex& index) const
  47. {
  48. if (!index.is_valid())
  49. return 1;
  50. auto& node = *static_cast<Node*>(index.internal_data());
  51. return node.child_count();
  52. }
  53. int DOMTreeModel::column_count(const GModelIndex&) const
  54. {
  55. return 1;
  56. }
  57. static String with_whitespace_collapsed(const StringView& string)
  58. {
  59. StringBuilder builder;
  60. for (int i = 0; i < string.length(); ++i) {
  61. if (isspace(string[i])) {
  62. builder.append(' ');
  63. while (i < string.length()) {
  64. if (isspace(string[i])) {
  65. ++i;
  66. continue;
  67. }
  68. builder.append(string[i]);
  69. break;
  70. }
  71. continue;
  72. }
  73. builder.append(string[i]);
  74. }
  75. return builder.to_string();
  76. }
  77. GVariant DOMTreeModel::data(const GModelIndex& index, Role role) const
  78. {
  79. auto* node = static_cast<Node*>(index.internal_data());
  80. if (role == Role::Icon) {
  81. if (node->is_element())
  82. return m_element_icon;
  83. // FIXME: More node type icons?
  84. return m_text_icon;
  85. }
  86. if (role == Role::Display) {
  87. if (node->is_text()) {
  88. return String::format("%s", with_whitespace_collapsed(to<Text>(*node).data()).characters());
  89. }
  90. return String::format("<%s>", node->tag_name().characters());
  91. }
  92. return {};
  93. }
  94. void DOMTreeModel::update()
  95. {
  96. did_update();
  97. }