Serenity Operating System
at master 143 lines 4.9 kB view raw
1/* 2 * Copyright (c) 2019-2020, Jesse Buhgaiar <jooster669@gmail.com> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/NonnullRefPtr.h> 11#include <AK/Vector.h> 12#include <LibGUI/Model.h> 13 14namespace GUI { 15 16template<typename T, typename Container = Vector<T>, typename ColumnNameListType = void> 17class ItemListModel : public Model { 18public: 19 static constexpr auto IsTwoDimensional = requires(Container data) { 20 requires !IsVoid<ColumnNameListType>; 21 data.at(0).at(0); 22 data.at(0).size(); 23 }; 24 25 // Substitute 'void' for a dummy u8. 26 using ColumnNamesT = Conditional<IsVoid<ColumnNameListType>, u8, ColumnNameListType>; 27 28 static NonnullRefPtr<ItemListModel> create(Container const& data, ColumnNamesT const& column_names, Optional<size_t> const& row_count = {}) 29 requires(IsTwoDimensional) 30 { 31 return adopt_ref(*new ItemListModel<T, Container, ColumnNameListType>(data, column_names, row_count)); 32 } 33 static NonnullRefPtr<ItemListModel> create(Container const& data, Optional<size_t> const& row_count = {}) 34 requires(!IsTwoDimensional) 35 { 36 return adopt_ref(*new ItemListModel<T, Container>(data, row_count)); 37 } 38 39 virtual ~ItemListModel() override = default; 40 41 virtual int row_count(ModelIndex const& index) const override 42 { 43 if (!index.is_valid()) 44 return m_provided_row_count.has_value() ? *m_provided_row_count : m_data.size(); 45 return 0; 46 } 47 48 virtual int column_count(ModelIndex const& index) const override 49 { 50 // if it's 2D (e.g. Vector<Vector<T>>) 51 if constexpr (IsTwoDimensional) { 52 if (index.is_valid()) 53 return m_data.at(index.row()).size(); 54 if (m_data.size()) 55 return m_data.at(0).size(); 56 return 0; 57 } 58 59 // Otherwise, let's just assume it's 1D. 60 return 1; 61 } 62 63 virtual DeprecatedString column_name(int index) const override 64 { 65 if constexpr (IsTwoDimensional) 66 return m_column_names[index]; 67 return "Data"; 68 } 69 70 virtual Variant data(ModelIndex const& index, ModelRole role) const override 71 { 72 if (role == ModelRole::TextAlignment) 73 return Gfx::TextAlignment::CenterLeft; 74 if (role == ModelRole::Display) { 75 if constexpr (IsTwoDimensional) 76 return m_data.at(index.row()).at(index.column()); 77 else 78 return m_data.at(index.row()); 79 } 80 81 return {}; 82 } 83 84 virtual TriState data_matches(GUI::ModelIndex const& index, GUI::Variant const& term) const override 85 { 86 if (index.data().as_string().contains(term.as_string(), CaseSensitivity::CaseInsensitive)) 87 return TriState::True; 88 return TriState::False; 89 } 90 91 virtual bool is_searchable() const override { return true; } 92 virtual Vector<GUI::ModelIndex> matches(StringView searching, unsigned flags, GUI::ModelIndex const&) override 93 { 94 Vector<GUI::ModelIndex> found_indices; 95 if constexpr (IsTwoDimensional) { 96 for (auto it = m_data.begin(); it != m_data.end(); ++it) { 97 for (auto it2d = (*it).begin(); it2d != (*it).end(); ++it2d) { 98 GUI::ModelIndex index = this->index(it.index(), it2d.index()); 99 if (!string_matches(data(index, ModelRole::Display).to_deprecated_string(), searching, flags)) 100 continue; 101 102 found_indices.append(index); 103 if (flags & FirstMatchOnly) 104 return found_indices; 105 } 106 } 107 } else { 108 for (auto it = m_data.begin(); it != m_data.end(); ++it) { 109 GUI::ModelIndex index = this->index(it.index()); 110 if (!string_matches(data(index, ModelRole::Display).to_deprecated_string(), searching, flags)) 111 continue; 112 113 found_indices.append(index); 114 if (flags & FirstMatchOnly) 115 return found_indices; 116 } 117 } 118 119 return found_indices; 120 } 121 122protected: 123 explicit ItemListModel(Container const& data, Optional<size_t> row_count = {}) 124 requires(!IsTwoDimensional) 125 : m_data(data) 126 , m_provided_row_count(move(row_count)) 127 { 128 } 129 130 explicit ItemListModel(Container const& data, ColumnNamesT const& column_names, Optional<size_t> row_count = {}) 131 requires(IsTwoDimensional) 132 : m_data(data) 133 , m_column_names(column_names) 134 , m_provided_row_count(move(row_count)) 135 { 136 } 137 138 Container const& m_data; 139 ColumnNamesT m_column_names; 140 Optional<size_t> m_provided_row_count; 141}; 142 143}