Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Badge.h>
30#include <AK/Function.h>
31#include <AK/HashTable.h>
32#include <AK/RefCounted.h>
33#include <AK/String.h>
34#include <LibGUI/ModelIndex.h>
35#include <LibGUI/Variant.h>
36#include <LibGfx/Forward.h>
37#include <LibGfx/TextAlignment.h>
38
39namespace GUI {
40
41enum class SortOrder {
42 None,
43 Ascending,
44 Descending
45};
46
47class Model : public RefCounted<Model> {
48public:
49 struct ColumnMetadata {
50 int preferred_width { 0 };
51 Gfx::TextAlignment text_alignment { Gfx::TextAlignment::CenterLeft };
52 const Gfx::Font* font { nullptr };
53 enum class Sortable {
54 False,
55 True,
56 };
57 Sortable sortable { Sortable::True };
58 };
59
60 enum class Role {
61 Display,
62 Sort,
63 Custom,
64 ForegroundColor,
65 BackgroundColor,
66 Icon,
67 Font,
68 DragData,
69 };
70
71 virtual ~Model();
72
73 virtual int row_count(const ModelIndex& = ModelIndex()) const = 0;
74 virtual int column_count(const ModelIndex& = ModelIndex()) const = 0;
75 virtual String row_name(int) const { return {}; }
76 virtual String column_name(int) const { return {}; }
77 virtual ColumnMetadata column_metadata(int) const { return {}; }
78 virtual Variant data(const ModelIndex&, Role = Role::Display) const = 0;
79 virtual void update() = 0;
80 virtual ModelIndex parent_index(const ModelIndex&) const { return {}; }
81 virtual ModelIndex index(int row, int column = 0, const ModelIndex& = ModelIndex()) const { return create_index(row, column); }
82 virtual ModelIndex sibling(int row, int column, const ModelIndex& parent) const;
83 virtual bool is_editable(const ModelIndex&) const { return false; }
84 virtual void set_data(const ModelIndex&, const Variant&) {}
85 virtual int tree_column() const { return 0; }
86 virtual bool accepts_drag(const ModelIndex&, const StringView& data_type);
87
88 bool is_valid(const ModelIndex& index) const
89 {
90 auto parent_index = this->parent_index(index);
91 return index.row() >= 0 && index.row() < row_count(parent_index) && index.column() >= 0 && index.column() < column_count(parent_index);
92 }
93
94 virtual int key_column() const { return -1; }
95 virtual SortOrder sort_order() const { return SortOrder::None; }
96 virtual void set_key_column_and_sort_order(int, SortOrder) {}
97
98 virtual StringView drag_data_type() const { return {}; }
99
100 void register_view(Badge<AbstractView>, AbstractView&);
101 void unregister_view(Badge<AbstractView>, AbstractView&);
102
103 Function<void()> on_update;
104
105protected:
106 Model();
107
108 void for_each_view(Function<void(AbstractView&)>);
109 void did_update();
110
111 ModelIndex create_index(int row, int column, const void* data = nullptr) const;
112
113private:
114 HashTable<AbstractView*> m_views;
115};
116
117inline ModelIndex ModelIndex::parent() const
118{
119 return m_model ? m_model->parent_index(*this) : ModelIndex();
120}
121
122}