Serenity Operating System
at master 193 lines 6.0 kB view raw
1/* 2 * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "ClassViewWidget.h" 8#include "HackStudio.h" 9#include "ProjectDeclarations.h" 10#include <AK/StdLibExtras.h> 11#include <LibGUI/BoxLayout.h> 12#include <string.h> 13 14namespace HackStudio { 15 16ClassViewWidget::ClassViewWidget() 17{ 18 set_layout<GUI::VerticalBoxLayout>(); 19 m_class_tree = add<GUI::TreeView>(); 20 21 m_class_tree->on_selection_change = [this] { 22 const auto& index = m_class_tree->selection().first(); 23 if (!index.is_valid()) 24 return; 25 26 auto* node = static_cast<const ClassViewNode*>(index.internal_data()); 27 if (!node->declaration) 28 return; 29 30 open_file(node->declaration->position.file, node->declaration->position.line, node->declaration->position.column); 31 }; 32} 33 34RefPtr<ClassViewModel> ClassViewModel::create() 35{ 36 return adopt_ref(*new ClassViewModel()); 37} 38 39int ClassViewModel::row_count(const GUI::ModelIndex& index) const 40{ 41 if (!index.is_valid()) 42 return m_root_scope.size(); 43 auto* node = static_cast<ClassViewNode*>(index.internal_data()); 44 return node->children.size(); 45} 46 47GUI::Variant ClassViewModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const 48{ 49 auto* node = static_cast<ClassViewNode const*>(index.internal_data()); 50 switch (role) { 51 case GUI::ModelRole::Display: { 52 return node->name; 53 } 54 case GUI::ModelRole::Icon: { 55 if (!node->declaration) 56 return {}; 57 auto icon = ProjectDeclarations::get_icon_for(node->declaration->type); 58 if (icon.has_value()) 59 return icon.value(); 60 return {}; 61 } 62 default: 63 return {}; 64 } 65} 66 67GUI::ModelIndex ClassViewModel::parent_index(const GUI::ModelIndex& index) const 68{ 69 if (!index.is_valid()) 70 return {}; 71 auto* child = static_cast<ClassViewNode const*>(index.internal_data()); 72 auto* parent = child->parent; 73 if (parent == nullptr) 74 return {}; 75 76 if (parent->parent == nullptr) { 77 for (size_t row = 0; row < m_root_scope.size(); row++) { 78 if (m_root_scope[row].ptr() == parent) 79 return create_index(row, 0, parent); 80 } 81 VERIFY_NOT_REACHED(); 82 } 83 for (size_t row = 0; row < parent->parent->children.size(); row++) { 84 ClassViewNode* child_at_row = parent->parent->children[row].ptr(); 85 if (child_at_row == parent) 86 return create_index(row, 0, parent); 87 } 88 VERIFY_NOT_REACHED(); 89} 90 91GUI::ModelIndex ClassViewModel::index(int row, int column, const GUI::ModelIndex& parent_index) const 92{ 93 if (!parent_index.is_valid()) 94 return create_index(row, column, m_root_scope[row].ptr()); 95 auto* parent = static_cast<ClassViewNode const*>(parent_index.internal_data()); 96 auto* child = parent->children[row].ptr(); 97 return create_index(row, column, child); 98} 99 100ClassViewModel::ClassViewModel() 101{ 102 m_root_scope.clear(); 103 ProjectDeclarations::the().for_each_declared_symbol([this](auto& decl) { 104 if (decl.type == CodeComprehension::DeclarationType::Class 105 || decl.type == CodeComprehension::DeclarationType::Struct 106 || decl.type == CodeComprehension::DeclarationType::Member 107 || decl.type == CodeComprehension::DeclarationType::Namespace) { 108 add_declaration(decl); 109 } 110 }); 111} 112 113static ClassViewNode& add_child_node(Vector<NonnullOwnPtr<ClassViewNode>>& children, NonnullOwnPtr<ClassViewNode>&& node_ptr, ClassViewNode* parent, CodeComprehension::Declaration const* declaration) 114{ 115 node_ptr->parent = parent; 116 node_ptr->declaration = declaration; 117 118 size_t inserted_index = 0; 119 ClassViewNode& node = *node_ptr; 120 // Insert into parent's children list, sorted lexicographically by name. 121 children.insert_before_matching( 122 move(node_ptr), [&node](auto& other_node) { 123 return strncmp(node.name.characters_without_null_termination(), other_node->name.characters_without_null_termination(), min(node.name.length(), other_node->name.length())) < 0; 124 }, 125 0, &inserted_index); 126 127 return *children.at(inserted_index); 128} 129 130void ClassViewModel::add_declaration(CodeComprehension::Declaration const& decl) 131{ 132 ClassViewNode* parent = nullptr; 133 auto scope_parts = decl.scope.view().split_view("::"sv); 134 135 if (!scope_parts.is_empty()) { 136 // Traverse declarations tree to the parent of 'decl' 137 for (auto& node : m_root_scope) { 138 if (node->name == scope_parts.first()) 139 parent = node; 140 } 141 142 if (parent == nullptr) { 143 m_root_scope.append(make<ClassViewNode>(scope_parts.first())); 144 parent = m_root_scope.last(); 145 } 146 147 for (size_t i = 1; i < scope_parts.size(); ++i) { 148 auto& scope = scope_parts[i]; 149 ClassViewNode* next { nullptr }; 150 for (auto& child : parent->children) { 151 if (child->name == scope) { 152 next = child; 153 break; 154 } 155 } 156 157 if (next) { 158 parent = next; 159 continue; 160 } 161 162 parent = &add_child_node(parent->children, make<ClassViewNode>(scope), parent, nullptr); 163 } 164 } 165 166 Vector<NonnullOwnPtr<ClassViewNode>>* children_of_parent = nullptr; 167 if (parent) { 168 children_of_parent = &parent->children; 169 } else { 170 children_of_parent = &m_root_scope; 171 } 172 173 bool already_exists = false; 174 for (auto& child : *children_of_parent) { 175 if (child->name == decl.name) { 176 already_exists = true; 177 if (!child->declaration) { 178 child->declaration = &decl; 179 } 180 break; 181 } 182 } 183 if (!already_exists) { 184 add_child_node(*children_of_parent, make<ClassViewNode>(decl.name), parent, &decl); 185 } 186} 187 188void ClassViewWidget::refresh() 189{ 190 m_class_tree->set_model(ClassViewModel::create()); 191} 192 193}