소스 검색

LibGUI: Expand GModelIndex a bit, adding internal data and model pointers.

This will be useful for implementing more complicated models.
Andreas Kling 6 년 전
부모
커밋
d02238af48

+ 1 - 1
Applications/FileManager/DirectoryModel.cpp

@@ -282,7 +282,7 @@ void DirectoryModel::open(const String& a_path)
     closedir(dirp);
     closedir(dirp);
     m_path = path;
     m_path = path;
     update();
     update();
-    set_selected_index({ 0, 0 });
+    set_selected_index(index(0, 0));
 }
 }
 
 
 void DirectoryModel::activate(const GModelIndex& index)
 void DirectoryModel::activate(const GModelIndex& index)

+ 7 - 1
Applications/FileManager/main.cpp

@@ -11,6 +11,7 @@
 #include <LibGUI/GInputBox.h>
 #include <LibGUI/GInputBox.h>
 #include <LibGUI/GMessageBox.h>
 #include <LibGUI/GMessageBox.h>
 #include <LibGUI/GProgressBar.h>
 #include <LibGUI/GProgressBar.h>
+#include <LibGUI/GTreeView.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <signal.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -48,7 +49,12 @@ int main(int argc, char** argv)
 
 
     auto* location_textbox = new GTextEditor(GTextEditor::SingleLine, location_toolbar);
     auto* location_textbox = new GTextEditor(GTextEditor::SingleLine, location_toolbar);
 
 
-    auto* directory_view = new DirectoryView(widget);
+    // FIXME: Implement an actual GSplitter widget.
+    auto* splitter = new GWidget(widget);
+    splitter->set_layout(make<GBoxLayout>(Orientation::Horizontal));
+    auto* tree_view = new GTreeView(splitter);
+    auto* directory_view = new DirectoryView(splitter);
+
     auto* statusbar = new GStatusBar(widget);
     auto* statusbar = new GStatusBar(widget);
 
 
     auto* progressbar = new GProgressBar(statusbar);
     auto* progressbar = new GProgressBar(statusbar);

+ 1 - 1
Applications/ProcessManager/ProcessTableView.cpp

@@ -33,5 +33,5 @@ pid_t ProcessTableView::selected_pid() const
 {
 {
     if (!model()->selected_index().is_valid())
     if (!model()->selected_index().is_valid())
         return -1;
         return -1;
-    return model()->data({ model()->selected_index().row(), ProcessModel::Column::PID }, GModel::Role::Sort).as_int();
+    return model()->data(model()->index(model()->selected_index().row(), ProcessModel::Column::PID), GModel::Role::Sort).as_int();
 }
 }

+ 14 - 14
LibGUI/GItemView.cpp

@@ -74,7 +74,7 @@ void GItemView::mousedown_event(GMouseEvent& event)
         auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
         auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
         for (int i = 0; i < item_count(); ++i) {
         for (int i = 0; i < item_count(); ++i) {
             if (item_rect(i).contains(adjusted_position)) {
             if (item_rect(i).contains(adjusted_position)) {
-                model()->set_selected_index({ i, 0 });
+                model()->set_selected_index(model()->index(i, 0));
                 update();
                 update();
                 return;
                 return;
             }
             }
@@ -117,7 +117,7 @@ void GItemView::paint_event(GPaintEvent& event)
         }
         }
 
 
         Rect item_rect = this->item_rect(item_index);
         Rect item_rect = this->item_rect(item_index);
-        GModelIndex model_index(item_index, m_model_column);
+        auto model_index = model()->index(item_index, m_model_column);
 
 
         auto icon = model()->data(model_index, GModel::Role::Icon);
         auto icon = model()->data(model_index, GModel::Role::Icon);
         auto item_text = model()->data(model_index, GModel::Role::Display);
         auto item_text = model()->data(model_index, GModel::Role::Display);
@@ -165,7 +165,7 @@ void GItemView::keydown_event(GKeyEvent& event)
         return;
         return;
     }
     }
     if (event.key() == KeyCode::Key_Home) {
     if (event.key() == KeyCode::Key_Home) {
-        GModelIndex new_index { 0, 0 };
+        auto new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -174,7 +174,7 @@ void GItemView::keydown_event(GKeyEvent& event)
         return;
         return;
     }
     }
     if (event.key() == KeyCode::Key_End) {
     if (event.key() == KeyCode::Key_End) {
-        GModelIndex new_index { model.row_count() - 1, 0 };
+        auto new_index = model.index(model.row_count() - 1, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -185,9 +185,9 @@ void GItemView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Up) {
     if (event.key() == KeyCode::Key_Up) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() - m_visual_column_count, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() - m_visual_column_count, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -198,9 +198,9 @@ void GItemView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Down) {
     if (event.key() == KeyCode::Key_Down) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() + m_visual_column_count, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() + m_visual_column_count, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -211,9 +211,9 @@ void GItemView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Left) {
     if (event.key() == KeyCode::Key_Left) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() - 1, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() - 1, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -224,9 +224,9 @@ void GItemView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Right) {
     if (event.key() == KeyCode::Key_Right) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() + 1, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() + 1, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -236,7 +236,7 @@ void GItemView::keydown_event(GKeyEvent& event)
     }
     }
     if (event.key() == KeyCode::Key_PageUp) {
     if (event.key() == KeyCode::Key_PageUp) {
         int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
         int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
-        GModelIndex new_index(max(0, model.selected_index().row() - items_per_page), model.selected_index().column());
+        auto new_index = model.index(max(0, model.selected_index().row() - items_per_page), model.selected_index().column());
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -246,7 +246,7 @@ void GItemView::keydown_event(GKeyEvent& event)
     }
     }
     if (event.key() == KeyCode::Key_PageDown) {
     if (event.key() == KeyCode::Key_PageDown) {
         int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
         int items_per_page = (visible_content_rect().height() / effective_item_size().height()) * m_visual_column_count;
-        GModelIndex new_index(min(model.row_count() - 1, model.selected_index().row() + items_per_page), model.selected_index().column());
+        auto new_index = model.index(min(model.row_count() - 1, model.selected_index().row() + items_per_page), model.selected_index().column());
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);

+ 5 - 0
LibGUI/GModel.cpp

@@ -44,3 +44,8 @@ void GModel::set_selected_index(const GModelIndex& index)
     if (m_activates_on_selection && is_valid(index))
     if (m_activates_on_selection && is_valid(index))
         activate(index);
         activate(index);
 }
 }
+
+GModelIndex GModel::create_index(int row, int column, void* data) const
+{
+    return GModelIndex(*this, row, column, data);
+}

+ 4 - 0
LibGUI/GModel.h

@@ -76,12 +76,16 @@ public:
     Function<void(GModel&)> on_model_update;
     Function<void(GModel&)> on_model_update;
     Function<void(const GModelIndex&)> on_selection_changed;
     Function<void(const GModelIndex&)> on_selection_changed;
 
 
+    virtual GModelIndex index(int row, int column) const { return create_index(row, column); }
+
 protected:
 protected:
     GModel();
     GModel();
 
 
     void for_each_view(Function<void(GAbstractView&)>);
     void for_each_view(Function<void(GAbstractView&)>);
     void did_update();
     void did_update();
 
 
+    GModelIndex create_index(int row, int column, void* data = nullptr) const;
+
 private:
 private:
     HashTable<GAbstractView*> m_views;
     HashTable<GAbstractView*> m_views;
     GModelIndex m_selected_index;
     GModelIndex m_selected_index;

+ 15 - 5
LibGUI/GModelIndex.h

@@ -1,21 +1,31 @@
 #pragma once
 #pragma once
 
 
+class GModel;
+
 class GModelIndex {
 class GModelIndex {
+    friend class GModel;
 public:
 public:
     GModelIndex() { }
     GModelIndex() { }
-    GModelIndex(int row, int column)
-        : m_row(row)
-        , m_column(column)
-    {
-    }
 
 
     bool is_valid() const { return m_row != -1 && m_column != -1; }
     bool is_valid() const { return m_row != -1 && m_column != -1; }
     int row() const { return m_row; }
     int row() const { return m_row; }
     int column() const { return m_column; }
     int column() const { return m_column; }
 
 
+    void* internal_data() const { return m_internal_data; }
+
     bool operator==(const GModelIndex& other) const { return m_row == other.m_row && m_column == other.m_column; }
     bool operator==(const GModelIndex& other) const { return m_row == other.m_row && m_column == other.m_column; }
 
 
 private:
 private:
+    GModelIndex(const GModel& model, int row, int column, void* internal_data)
+        : m_model(&model)
+        , m_row(row)
+        , m_column(column)
+        , m_internal_data(internal_data)
+    {
+    }
+
+    const GModel* m_model { nullptr };
     int m_row { -1 };
     int m_row { -1 };
     int m_column { -1 };
     int m_column { -1 };
+    void* m_internal_data { nullptr };
 };
 };

+ 4 - 4
LibGUI/GSortingProxyModel.cpp

@@ -32,7 +32,7 @@ GModelIndex GSortingProxyModel::map_to_target(const GModelIndex& index) const
         return { };
         return { };
     if (index.row() >= row_count() || index.column() >= column_count())
     if (index.row() >= row_count() || index.column() >= column_count())
         return { };
         return { };
-    return { m_row_mappings[index.row()], index.column() };
+    return target().index(m_row_mappings[index.row()], index.column());
 }
 }
 
 
 String GSortingProxyModel::row_name(int index) const
 String GSortingProxyModel::row_name(int index) const
@@ -86,8 +86,8 @@ void GSortingProxyModel::resort()
     if (m_key_column == -1)
     if (m_key_column == -1)
         return;
         return;
     quick_sort(m_row_mappings.begin(), m_row_mappings.end(), [&] (auto row1, auto row2) -> bool {
     quick_sort(m_row_mappings.begin(), m_row_mappings.end(), [&] (auto row1, auto row2) -> bool {
-        auto data1 = target().data({ row1, m_key_column }, GModel::Role::Sort);
-        auto data2 = target().data({ row2, m_key_column }, GModel::Role::Sort);
+        auto data1 = target().data(target().index(row1, m_key_column), GModel::Role::Sort);
+        auto data2 = target().data(target().index(row2, m_key_column), GModel::Role::Sort);
         if (data1 == data2)
         if (data1 == data2)
             return 0;
             return 0;
         bool is_less_than = data1 < data2;
         bool is_less_than = data1 < data2;
@@ -97,7 +97,7 @@ void GSortingProxyModel::resort()
         // Preserve selection.
         // Preserve selection.
         for (int i = 0; i < row_count; ++i) {
         for (int i = 0; i < row_count; ++i) {
             if (m_row_mappings[i] == previously_selected_target_row) {
             if (m_row_mappings[i] == previously_selected_target_row) {
-                set_selected_index({ i, 0 });
+                set_selected_index(index(i, 0));
                 break;
                 break;
             }
             }
         }
         }

+ 8 - 8
LibGUI/GTableView.cpp

@@ -86,7 +86,7 @@ void GTableView::mousedown_event(GMouseEvent& event)
         auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
         auto adjusted_position = event.position().translated(0, vertical_scrollbar().value());
         for (int i = 0; i < item_count(); ++i) {
         for (int i = 0; i < item_count(); ++i) {
             if (row_rect(i).contains(adjusted_position)) {
             if (row_rect(i).contains(adjusted_position)) {
-                model()->set_selected_index({ i, 0 });
+                model()->set_selected_index(model()->index(i, 0));
                 update();
                 update();
                 return;
                 return;
             }
             }
@@ -143,7 +143,7 @@ void GTableView::paint_event(GPaintEvent& event)
                 auto cell_rect_for_fill = cell_rect.inflated(horizontal_padding() * 2, 0);
                 auto cell_rect_for_fill = cell_rect.inflated(horizontal_padding() * 2, 0);
                 painter.fill_rect(cell_rect_for_fill, key_column_background_color);
                 painter.fill_rect(cell_rect_for_fill, key_column_background_color);
             }
             }
-            GModelIndex cell_index(row_index, column_index);
+            auto cell_index = model()->index(row_index, column_index);
             auto data = model()->data(cell_index);
             auto data = model()->data(cell_index);
             if (data.is_bitmap()) {
             if (data.is_bitmap()) {
                 painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect());
                 painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect());
@@ -228,9 +228,9 @@ void GTableView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Up) {
     if (event.key() == KeyCode::Key_Up) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() - 1, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() - 1, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -241,9 +241,9 @@ void GTableView::keydown_event(GKeyEvent& event)
     if (event.key() == KeyCode::Key_Down) {
     if (event.key() == KeyCode::Key_Down) {
         GModelIndex new_index;
         GModelIndex new_index;
         if (model.selected_index().is_valid())
         if (model.selected_index().is_valid())
-            new_index = { model.selected_index().row() + 1, model.selected_index().column() };
+            new_index = model.index(model.selected_index().row() + 1, model.selected_index().column());
         else
         else
-            new_index = { 0, 0 };
+            new_index = model.index(0, 0);
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -253,7 +253,7 @@ void GTableView::keydown_event(GKeyEvent& event)
     }
     }
     if (event.key() == KeyCode::Key_PageUp) {
     if (event.key() == KeyCode::Key_PageUp) {
         int items_per_page = visible_content_rect().height() / item_height();
         int items_per_page = visible_content_rect().height() / item_height();
-        GModelIndex new_index(max(0, model.selected_index().row() - items_per_page), model.selected_index().column());
+        auto new_index = model.index(max(0, model.selected_index().row() - items_per_page), model.selected_index().column());
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);
@@ -263,7 +263,7 @@ void GTableView::keydown_event(GKeyEvent& event)
     }
     }
     if (event.key() == KeyCode::Key_PageDown) {
     if (event.key() == KeyCode::Key_PageDown) {
         int items_per_page = visible_content_rect().height() / item_height();
         int items_per_page = visible_content_rect().height() / item_height();
-        GModelIndex new_index(min(model.row_count() - 1, model.selected_index().row() + items_per_page), model.selected_index().column());
+        auto new_index = model.index(min(model.row_count() - 1, model.selected_index().row() + items_per_page), model.selected_index().column());
         if (model.is_valid(new_index)) {
         if (model.is_valid(new_index)) {
             model.set_selected_index(new_index);
             model.set_selected_index(new_index);
             scroll_into_view(new_index, Orientation::Vertical);
             scroll_into_view(new_index, Orientation::Vertical);

+ 35 - 0
LibGUI/GTreeView.cpp

@@ -1,9 +1,44 @@
 #include <LibGUI/GTreeView.h>
 #include <LibGUI/GTreeView.h>
 #include <LibGUI/GPainter.h>
 #include <LibGUI/GPainter.h>
 
 
+class TestModel : public GModel {
+public:
+    static Retained<TestModel> create() { return adopt(*new TestModel); }
+
+    virtual int row_count(const GModelIndex& = GModelIndex()) const;
+    virtual int column_count(const GModelIndex& = GModelIndex()) const;
+    virtual GVariant data(const GModelIndex&, Role = Role::Display) const;
+    virtual void update();
+    virtual ColumnMetadata column_metadata(int) const { return { 100 }; }
+};
+
+int TestModel::row_count(const GModelIndex& index) const
+{
+    return 0;
+}
+
+int TestModel::column_count(const GModelIndex&) const
+{
+    return 1;
+}
+
+void TestModel::update()
+{
+}
+
+GVariant TestModel::data(const GModelIndex&, Role) const
+{
+    return { };
+}
+
 GTreeView::GTreeView(GWidget* parent)
 GTreeView::GTreeView(GWidget* parent)
     : GAbstractView(parent)
     : GAbstractView(parent)
 {
 {
+    set_frame_shape(GFrame::Shape::Container);
+    set_frame_shadow(GFrame::Shadow::Sunken);
+    set_frame_thickness(2);
+
+    set_model(TestModel::create());
 }
 }
 
 
 GTreeView::~GTreeView()
 GTreeView::~GTreeView()