/* * Copyright (c) 2019-2020, Jesse Buhgaiar * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace GUI { template, typename ColumnNameListType = void> class ItemListModel : public Model { public: static constexpr auto IsTwoDimensional = requires(Container data) { requires !IsVoid; data.at(0).at(0); data.at(0).size(); }; // Substitute 'void' for a dummy u8. using ColumnNamesT = Conditional, u8, ColumnNameListType>; static NonnullRefPtr create(Container const& data, ColumnNamesT const& column_names, Optional const& row_count = {}) requires(IsTwoDimensional) { return adopt_ref(*new ItemListModel(data, column_names, row_count)); } static NonnullRefPtr create(Container const& data, Optional const& row_count = {}) requires(!IsTwoDimensional) { return adopt_ref(*new ItemListModel(data, row_count)); } virtual ~ItemListModel() override { } virtual int row_count(ModelIndex const& index) const override { if (!index.is_valid()) return m_provided_row_count.has_value() ? *m_provided_row_count : m_data.size(); return 0; } virtual int column_count(ModelIndex const& index) const override { // if it's 2D (e.g. Vector>) if constexpr (IsTwoDimensional) { if (index.is_valid()) return m_data.at(index.row()).size(); if (m_data.size()) return m_data.at(0).size(); return 0; } // Otherwise, let's just assume it's 1D. return 1; } virtual String column_name(int index) const override { if constexpr (IsTwoDimensional) return m_column_names[index]; return "Data"; } virtual Variant data(ModelIndex const& index, ModelRole role) const override { if (role == ModelRole::TextAlignment) return Gfx::TextAlignment::CenterLeft; if (role == ModelRole::Display) { if constexpr (IsTwoDimensional) return m_data.at(index.row()).at(index.column()); else return m_data.at(index.row()); } return {}; } virtual TriState data_matches(GUI::ModelIndex const& index, GUI::Variant const& term) const override { if (index.data().as_string().contains(term.as_string(), CaseSensitivity::CaseInsensitive)) return TriState::True; return TriState::False; } virtual bool is_searchable() const override { return true; } virtual Vector matches(StringView searching, unsigned flags, GUI::ModelIndex const&) override { Vector found_indices; if constexpr (IsTwoDimensional) { for (auto it = m_data.begin(); it != m_data.end(); ++it) { for (auto it2d = (*it).begin(); it2d != (*it).end(); ++it2d) { GUI::ModelIndex index = this->index(it.index(), it2d.index()); if (!string_matches(data(index, ModelRole::Display).to_string(), searching, flags)) continue; found_indices.append(index); if (flags & FirstMatchOnly) return found_indices; } } } else { for (auto it = m_data.begin(); it != m_data.end(); ++it) { GUI::ModelIndex index = this->index(it.index()); if (!string_matches(data(index, ModelRole::Display).to_string(), searching, flags)) continue; found_indices.append(index); if (flags & FirstMatchOnly) return found_indices; } } return found_indices; } protected: explicit ItemListModel(Container const& data, Optional row_count = {}) requires(!IsTwoDimensional) : m_data(data) , m_provided_row_count(move(row_count)) { } explicit ItemListModel(Container const& data, ColumnNamesT const& column_names, Optional row_count = {}) requires(IsTwoDimensional) : m_data(data) , m_column_names(column_names) , m_provided_row_count(move(row_count)) { } Container const& m_data; ColumnNamesT m_column_names; Optional m_provided_row_count; }; }