ManualModel.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "ManualModel.h"
  7. #include "ManualNode.h"
  8. #include "ManualPageNode.h"
  9. #include "ManualSectionNode.h"
  10. #include <AK/Try.h>
  11. static ManualSectionNode s_sections[] = {
  12. { "1", "User programs" },
  13. { "2", "System calls" },
  14. { "3", "Library functions" },
  15. { "4", "Special files" },
  16. { "5", "File formats" },
  17. { "6", "Games" },
  18. { "7", "Miscellanea" },
  19. { "8", "Sysadmin tools" }
  20. };
  21. ManualModel::ManualModel()
  22. {
  23. m_section_open_icon.set_bitmap_for_size(16, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/book-open.png").release_value_but_fixme_should_propagate_errors());
  24. m_section_icon.set_bitmap_for_size(16, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/book.png").release_value_but_fixme_should_propagate_errors());
  25. m_page_icon.set_bitmap_for_size(16, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/filetype-unknown.png").release_value_but_fixme_should_propagate_errors());
  26. }
  27. Optional<GUI::ModelIndex> ManualModel::index_from_path(StringView path) const
  28. {
  29. for (int section = 0; section < row_count(); ++section) {
  30. auto parent_index = index(section, 0);
  31. for (int row = 0; row < row_count(parent_index); ++row) {
  32. auto child_index = index(row, 0, parent_index);
  33. auto* node = static_cast<const ManualNode*>(child_index.internal_data());
  34. if (!node->is_page())
  35. continue;
  36. auto* page = static_cast<const ManualPageNode*>(node);
  37. if (page->path() != path)
  38. continue;
  39. return child_index;
  40. }
  41. }
  42. return {};
  43. }
  44. String ManualModel::page_name(const GUI::ModelIndex& index) const
  45. {
  46. if (!index.is_valid())
  47. return {};
  48. auto* node = static_cast<const ManualNode*>(index.internal_data());
  49. if (!node->is_page())
  50. return {};
  51. auto* page = static_cast<const ManualPageNode*>(node);
  52. return page->name();
  53. }
  54. String ManualModel::page_path(const GUI::ModelIndex& index) const
  55. {
  56. if (!index.is_valid())
  57. return {};
  58. auto* node = static_cast<const ManualNode*>(index.internal_data());
  59. if (!node->is_page())
  60. return {};
  61. auto* page = static_cast<const ManualPageNode*>(node);
  62. return page->path();
  63. }
  64. ErrorOr<StringView> ManualModel::page_view(String const& path) const
  65. {
  66. if (path.is_empty())
  67. return StringView {};
  68. {
  69. // Check if we've got it cached already.
  70. auto mapped_file = m_mapped_files.get(path);
  71. if (mapped_file.has_value())
  72. return StringView { mapped_file.value()->bytes() };
  73. }
  74. auto file = TRY(Core::MappedFile::map(path));
  75. StringView view { file->bytes() };
  76. m_mapped_files.set(path, move(file));
  77. return view;
  78. }
  79. String ManualModel::page_and_section(const GUI::ModelIndex& index) const
  80. {
  81. if (!index.is_valid())
  82. return {};
  83. auto* node = static_cast<const ManualNode*>(index.internal_data());
  84. if (!node->is_page())
  85. return {};
  86. auto* page = static_cast<const ManualPageNode*>(node);
  87. auto* section = static_cast<const ManualSectionNode*>(page->parent());
  88. return String::formatted("{}({})", page->name(), section->section_name());
  89. }
  90. GUI::ModelIndex ManualModel::index(int row, int column, const GUI::ModelIndex& parent_index) const
  91. {
  92. if (!parent_index.is_valid())
  93. return create_index(row, column, &s_sections[row]);
  94. auto* parent = static_cast<const ManualNode*>(parent_index.internal_data());
  95. auto* child = &parent->children()[row];
  96. return create_index(row, column, child);
  97. }
  98. GUI::ModelIndex ManualModel::parent_index(const GUI::ModelIndex& index) const
  99. {
  100. if (!index.is_valid())
  101. return {};
  102. auto* child = static_cast<const ManualNode*>(index.internal_data());
  103. auto* parent = child->parent();
  104. if (parent == nullptr)
  105. return {};
  106. if (parent->parent() == nullptr) {
  107. for (size_t row = 0; row < sizeof(s_sections) / sizeof(s_sections[0]); row++)
  108. if (&s_sections[row] == parent)
  109. return create_index(row, 0, parent);
  110. VERIFY_NOT_REACHED();
  111. }
  112. for (size_t row = 0; row < parent->parent()->children().size(); row++) {
  113. ManualNode* child_at_row = &parent->parent()->children()[row];
  114. if (child_at_row == parent)
  115. return create_index(row, 0, parent);
  116. }
  117. VERIFY_NOT_REACHED();
  118. }
  119. int ManualModel::row_count(const GUI::ModelIndex& index) const
  120. {
  121. if (!index.is_valid())
  122. return sizeof(s_sections) / sizeof(s_sections[0]);
  123. auto* node = static_cast<const ManualNode*>(index.internal_data());
  124. return node->children().size();
  125. }
  126. int ManualModel::column_count(const GUI::ModelIndex&) const
  127. {
  128. return 1;
  129. }
  130. GUI::Variant ManualModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
  131. {
  132. auto* node = static_cast<const ManualNode*>(index.internal_data());
  133. switch (role) {
  134. case GUI::ModelRole::Search:
  135. if (!node->is_page())
  136. return {};
  137. return String(page_view(page_path(index)).value());
  138. case GUI::ModelRole::Display:
  139. return node->name();
  140. case GUI::ModelRole::Icon:
  141. if (node->is_page())
  142. return m_page_icon;
  143. if (node->is_open())
  144. return m_section_open_icon;
  145. return m_section_icon;
  146. default:
  147. return {};
  148. }
  149. }
  150. void ManualModel::update_section_node_on_toggle(const GUI::ModelIndex& index, const bool open)
  151. {
  152. auto* node = static_cast<ManualSectionNode*>(index.internal_data());
  153. node->set_open(open);
  154. }
  155. TriState ManualModel::data_matches(const GUI::ModelIndex& index, const GUI::Variant& term) const
  156. {
  157. auto name = page_name(index);
  158. if (name.contains(term.as_string()))
  159. return TriState::True;
  160. auto view_result = page_view(page_path(index));
  161. if (view_result.is_error() || view_result.value().is_empty())
  162. return TriState::False;
  163. return view_result.value().contains(term.as_string()) ? TriState::True : TriState::False;
  164. }