FilteringProxyModel.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibGUI/FilteringProxyModel.h>
  7. namespace GUI {
  8. ModelIndex FilteringProxyModel::index(int row, int column, ModelIndex const& parent_index) const
  9. {
  10. int parent_row = parent_index.row();
  11. if (!parent_index.is_valid())
  12. parent_row = 0;
  13. return create_index(parent_row + row, column);
  14. }
  15. int FilteringProxyModel::row_count(ModelIndex const&) const
  16. {
  17. return m_matching_indices.size();
  18. }
  19. int FilteringProxyModel::column_count(ModelIndex const& index) const
  20. {
  21. if (!index.is_valid())
  22. return m_model->column_count({});
  23. if ((size_t)index.row() > m_matching_indices.size() || index.row() < 0)
  24. return 0;
  25. return m_model->column_count(m_matching_indices[index.row()]);
  26. }
  27. Variant FilteringProxyModel::data(ModelIndex const& index, ModelRole role) const
  28. {
  29. if (!index.is_valid())
  30. return {};
  31. if ((size_t)index.row() > m_matching_indices.size() || index.row() < 0)
  32. return {};
  33. // FIXME: Support hierarchical models (with a non-empty index.parent()).
  34. auto underlying_index = m_model->index(m_matching_indices[index.row()].row(), index.column(), {});
  35. return underlying_index.data(role);
  36. }
  37. void FilteringProxyModel::invalidate()
  38. {
  39. filter();
  40. did_update();
  41. }
  42. void FilteringProxyModel::filter()
  43. {
  44. m_matching_indices.clear();
  45. Function<void(ModelIndex&)> add_matching = [&](ModelIndex& parent_index) {
  46. for (auto i = 0; i < m_model->row_count(parent_index); ++i) {
  47. auto index = m_model->index(i, 0, parent_index);
  48. if (!index.is_valid())
  49. continue;
  50. auto filter_matches = m_model->data_matches(index, m_filter_term);
  51. bool matches = filter_matches == TriState::True;
  52. if (filter_matches == TriState::Unknown) {
  53. auto data = index.data();
  54. if (data.is_string() && data.as_string().contains(m_filter_term))
  55. matches = true;
  56. }
  57. if (matches)
  58. m_matching_indices.append(index);
  59. add_matching(index);
  60. }
  61. };
  62. ModelIndex parent_index;
  63. add_matching(parent_index);
  64. }
  65. void FilteringProxyModel::set_filter_term(StringView term)
  66. {
  67. if (m_filter_term == term)
  68. return;
  69. m_filter_term = term;
  70. invalidate();
  71. }
  72. ModelIndex FilteringProxyModel::map(ModelIndex const& index) const
  73. {
  74. if (!index.is_valid())
  75. return {};
  76. auto row = index.row();
  77. if (m_matching_indices.size() > (size_t)row)
  78. return m_matching_indices[row];
  79. return {};
  80. }
  81. bool FilteringProxyModel::is_searchable() const
  82. {
  83. return m_model->is_searchable();
  84. }
  85. Vector<ModelIndex> FilteringProxyModel::matches(StringView searching, unsigned flags, ModelIndex const& index)
  86. {
  87. auto found_indices = m_model->matches(searching, flags, index);
  88. for (size_t i = 0; i < found_indices.size(); i++)
  89. found_indices[i] = map(found_indices[i]);
  90. return found_indices;
  91. }
  92. }