Changes the filter-text and refilters the data
| 168 | |
| 169 | ///Changes the filter-text and refilters the data |
| 170 | void setFilter(const QStringList& text) |
| 171 | { |
| 172 | if (m_oldFilterText == text) { |
| 173 | return; |
| 174 | } |
| 175 | if (text.isEmpty()) { |
| 176 | clearFilter(); |
| 177 | return; |
| 178 | } |
| 179 | |
| 180 | QVector<Item> filterBase = m_filtered; |
| 181 | |
| 182 | if (m_oldFilterText.isEmpty()) { |
| 183 | filterBase = m_items; |
| 184 | // m_filtered either hasn't been modified after construction or is shared with m_items after a call |
| 185 | // to clearFilter(). Assign a default-initialized value to m_filtered in order to avoid detaching |
| 186 | // it and copying its items to a new buffer when m_filtered is resized below. This copying would be |
| 187 | // a waste of CPU time, because new values are immediately assigned to all elements of m_filtered. |
| 188 | m_filtered = {}; |
| 189 | } else if (m_oldFilterText.mid(0, m_oldFilterText.count() - 1) == text.mid(0, text.count() - 1) |
| 190 | && text.last().startsWith(m_oldFilterText.last())) { |
| 191 | //Good, the prefix is the same, and the last item has been extended |
| 192 | } else if (m_oldFilterText.size() == text.size() - 1 && m_oldFilterText == text.mid(0, text.size() - 1)) { |
| 193 | //Good, an item has been added |
| 194 | } else { |
| 195 | //Start filtering based on the whole data, there was a big change to the filter |
| 196 | filterBase = m_items; |
| 197 | } |
| 198 | |
| 199 | QVector<QPair<int, int>> matches; |
| 200 | for (int i = 0, c = filterBase.size(); i < c; ++i) { |
| 201 | const auto& data = filterBase.at(i); |
| 202 | const auto matchQuality = matchPathFilter(static_cast<Parent*>(this)->itemPath(data), text, |
| 203 | static_cast<Parent*>(this)->itemPrefixPath(data)); |
| 204 | if (matchQuality == -1) { |
| 205 | continue; |
| 206 | } |
| 207 | matches.push_back({matchQuality, i}); |
| 208 | } |
| 209 | |
| 210 | std::stable_sort(matches.begin(), matches.end(), |
| 211 | [](const QPair<int, int>& lhs, const QPair<int, int>& rhs) |
| 212 | { |
| 213 | return lhs.first < rhs.first; |
| 214 | }); |
| 215 | m_filtered.resize(matches.size()); |
| 216 | std::transform(matches.begin(), matches.end(), m_filtered.begin(), |
| 217 | [&filterBase](const QPair<int, int>& match) { |
| 218 | return filterBase.at(match.second); |
| 219 | }); |
| 220 | m_oldFilterText = text; |
| 221 | } |
| 222 | |
| 223 | private: |
| 224 | ///Clears the filter, but not the data. |
nothing calls this directly
no test coverage detected