Serenity Operating System
at portability 156 lines 5.1 kB view raw
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#include <AK/QuickSort.h> 28#include <LibGUI/AbstractView.h> 29#include <LibGUI/SortingProxyModel.h> 30#include <stdio.h> 31#include <stdlib.h> 32 33namespace GUI { 34 35SortingProxyModel::SortingProxyModel(NonnullRefPtr<Model>&& target) 36 : m_target(move(target)) 37 , m_key_column(-1) 38{ 39 m_target->on_update = [this] { 40 resort(); 41 }; 42} 43 44SortingProxyModel::~SortingProxyModel() 45{ 46} 47 48int SortingProxyModel::row_count(const ModelIndex& index) const 49{ 50 return target().row_count(index); 51} 52 53int SortingProxyModel::column_count(const ModelIndex& index) const 54{ 55 return target().column_count(index); 56} 57 58ModelIndex SortingProxyModel::map_to_target(const ModelIndex& index) const 59{ 60 if (!index.is_valid()) 61 return {}; 62 if (static_cast<size_t>(index.row()) >= m_row_mappings.size() || index.column() >= column_count()) 63 return {}; 64 return target().index(m_row_mappings[index.row()], index.column()); 65} 66 67String SortingProxyModel::row_name(int index) const 68{ 69 return target().row_name(index); 70} 71 72String SortingProxyModel::column_name(int index) const 73{ 74 return target().column_name(index); 75} 76 77Model::ColumnMetadata SortingProxyModel::column_metadata(int index) const 78{ 79 return target().column_metadata(index); 80} 81 82Variant SortingProxyModel::data(const ModelIndex& index, Role role) const 83{ 84 auto target_index = map_to_target(index); 85 if (!target_index.is_valid()) { 86 dbg() << "BUG! SortingProxyModel: Unable to convert " << index << " to target"; 87 return {}; 88 } 89 return target().data(map_to_target(index), role); 90} 91 92void SortingProxyModel::update() 93{ 94 target().update(); 95} 96 97StringView SortingProxyModel::drag_data_type() const 98{ 99 return target().drag_data_type(); 100} 101 102void SortingProxyModel::set_key_column_and_sort_order(int column, SortOrder sort_order) 103{ 104 if (column == m_key_column && sort_order == m_sort_order) 105 return; 106 107 ASSERT(column >= 0 && column < column_count()); 108 m_key_column = column; 109 m_sort_order = sort_order; 110 resort(); 111} 112 113void SortingProxyModel::resort() 114{ 115 auto old_row_mappings = m_row_mappings; 116 int row_count = target().row_count(); 117 m_row_mappings.resize(row_count); 118 for (int i = 0; i < row_count; ++i) 119 m_row_mappings[i] = i; 120 if (m_key_column == -1) { 121 did_update(); 122 return; 123 } 124 quick_sort(m_row_mappings.begin(), m_row_mappings.end(), [&](auto row1, auto row2) -> bool { 125 auto data1 = target().data(target().index(row1, m_key_column), Model::Role::Sort); 126 auto data2 = target().data(target().index(row2, m_key_column), Model::Role::Sort); 127 if (data1 == data2) 128 return 0; 129 bool is_less_than; 130 if (data1.is_string() && data2.is_string() && !m_sorting_case_sensitive) 131 is_less_than = data1.as_string().to_lowercase() < data2.as_string().to_lowercase(); 132 else 133 is_less_than = data1 < data2; 134 return m_sort_order == SortOrder::Ascending ? is_less_than : !is_less_than; 135 }); 136 did_update(); 137 for_each_view([&](AbstractView& view) { 138 auto& selection = view.selection(); 139 Vector<ModelIndex> selected_indexes_in_target; 140 selection.for_each_index([&](const ModelIndex& index) { 141 selected_indexes_in_target.append(target().index(old_row_mappings[index.row()], index.column())); 142 }); 143 144 selection.clear(); 145 for (auto& index : selected_indexes_in_target) { 146 for (size_t i = 0; i < m_row_mappings.size(); ++i) { 147 if (m_row_mappings[i] == index.row()) { 148 selection.add(this->index(i, index.column())); 149 continue; 150 } 151 } 152 } 153 }); 154} 155 156}