FilteringProxyModel.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/InsertionSort.h>
  7. #include <LibGUI/FilteringProxyModel.h>
  8. namespace GUI {
  9. ModelIndex FilteringProxyModel::index(int row, int column, ModelIndex const& parent_index) const
  10. {
  11. int parent_row = parent_index.row();
  12. if (!parent_index.is_valid())
  13. parent_row = 0;
  14. return create_index(parent_row + row, column);
  15. }
  16. int FilteringProxyModel::row_count(ModelIndex const&) const
  17. {
  18. return m_matching_indices.size();
  19. }
  20. int FilteringProxyModel::column_count(ModelIndex const& index) const
  21. {
  22. if (!index.is_valid())
  23. return m_model->column_count({});
  24. if ((size_t)index.row() > m_matching_indices.size() || index.row() < 0)
  25. return 0;
  26. return m_model->column_count(m_matching_indices[index.row()].index);
  27. }
  28. ErrorOr<String> FilteringProxyModel::column_name(int column) const
  29. {
  30. return m_model->column_name(column);
  31. }
  32. Variant FilteringProxyModel::data(ModelIndex const& index, ModelRole role) const
  33. {
  34. if (!index.is_valid())
  35. return {};
  36. if ((size_t)index.row() > m_matching_indices.size() || index.row() < 0)
  37. return {};
  38. auto matching_index = m_matching_indices[index.row()].index;
  39. auto underlying_index = m_model->index(matching_index.row(), index.column(), matching_index.parent());
  40. return underlying_index.data(role);
  41. }
  42. void FilteringProxyModel::invalidate()
  43. {
  44. filter();
  45. did_update();
  46. }
  47. void FilteringProxyModel::filter()
  48. {
  49. m_matching_indices.clear();
  50. Function<void(ModelIndex&)> add_matching = [&](ModelIndex& parent_index) {
  51. for (auto i = 0; i < m_model->row_count(parent_index); ++i) {
  52. auto index = m_model->index(i, 0, parent_index);
  53. if (!index.is_valid())
  54. continue;
  55. auto match_result = m_model->data_matches(index, m_filter_term);
  56. bool matches = match_result.matched == TriState::True;
  57. auto score = match_result.score;
  58. if (match_result.matched == TriState::Unknown) {
  59. auto data = index.data();
  60. if (data.is_string() && data.as_string().contains(m_filter_term)) {
  61. matches = true;
  62. score = 0;
  63. }
  64. }
  65. if (matches)
  66. m_matching_indices.append({ index, score });
  67. add_matching(index);
  68. }
  69. };
  70. ModelIndex parent_index;
  71. add_matching(parent_index);
  72. if (has_flag(m_filtering_options, FilteringOptions::SortByScore))
  73. // Use a stable sort, so that indices with equal scores don't swap positions.
  74. insertion_sort(m_matching_indices, [](auto const& a, auto const& b) { return b.score < a.score; });
  75. }
  76. void FilteringProxyModel::set_filter_term(StringView term)
  77. {
  78. if (m_filter_term == term)
  79. return;
  80. m_filter_term = term;
  81. invalidate();
  82. }
  83. ModelIndex FilteringProxyModel::map(ModelIndex const& index) const
  84. {
  85. if (!index.is_valid())
  86. return {};
  87. auto row = index.row();
  88. if (m_matching_indices.size() > (size_t)row)
  89. return m_matching_indices[row].index;
  90. return {};
  91. }
  92. bool FilteringProxyModel::is_searchable() const
  93. {
  94. return m_model->is_searchable();
  95. }
  96. Vector<ModelIndex> FilteringProxyModel::matches(StringView searching, unsigned flags, ModelIndex const& index)
  97. {
  98. auto found_indices = m_model->matches(searching, flags, index);
  99. for (size_t i = 0; i < found_indices.size(); i++)
  100. found_indices[i] = map(found_indices[i]);
  101. return found_indices;
  102. }
  103. }