/src/libreoffice/svl/source/items/IndexedStyleSheets.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | |
11 | | #include <svl/IndexedStyleSheets.hxx> |
12 | | #include <svl/style.hxx> |
13 | | |
14 | | #include <stdexcept> |
15 | | #include <algorithm> |
16 | | #include <utility> |
17 | | |
18 | | |
19 | | namespace { |
20 | | size_t family_to_index(SfxStyleFamily family) |
21 | 17.7M | { |
22 | 17.7M | switch (family) { |
23 | 0 | case SfxStyleFamily::Char: |
24 | 0 | return 0; |
25 | 786k | case SfxStyleFamily::Para: |
26 | 786k | return 1; |
27 | 65.0k | case SfxStyleFamily::Frame: |
28 | 65.0k | return 2; |
29 | 16.6M | case SfxStyleFamily::Page: |
30 | 16.6M | return 3; |
31 | 233k | case SfxStyleFamily::Pseudo: |
32 | 233k | return 4; |
33 | 0 | case SfxStyleFamily::Table: |
34 | 0 | return 5; |
35 | 0 | default: break; |
36 | 17.7M | } |
37 | 17.7M | assert(false); // only for compiler warning. all cases are handled in the switch |
38 | 0 | return 0; |
39 | 17.7M | } |
40 | | } |
41 | | |
42 | | namespace svl { |
43 | | |
44 | | IndexedStyleSheets::IndexedStyleSheets() |
45 | 287k | { |
46 | 287k | } |
47 | | |
48 | | void IndexedStyleSheets::Register(SfxStyleSheetBase& style, sal_Int32 pos) |
49 | 2.12M | { |
50 | 2.12M | mPositionsByName.insert(std::make_pair(style.GetName(), pos)); |
51 | 2.12M | size_t position = family_to_index(style.GetFamily()); |
52 | 2.12M | mStyleSheetsByFamily.at(position).push_back(&style); |
53 | 2.12M | } |
54 | | |
55 | | void |
56 | | IndexedStyleSheets::Reindex() |
57 | 10.7k | { |
58 | 10.7k | mPositionsByName.clear(); |
59 | 75.2k | for (size_t i = 0; i < NUMBER_OF_FAMILIES; i++) { |
60 | 64.5k | mStyleSheetsByFamily[i].clear(); |
61 | 64.5k | } |
62 | | |
63 | 10.7k | sal_Int32 i = 0; |
64 | 1.34M | for (const auto& rxStyleSheet : mStyleSheets) { |
65 | 1.34M | SfxStyleSheetBase* p = rxStyleSheet.get(); |
66 | 1.34M | Register(*p, i); |
67 | 1.34M | ++i; |
68 | 1.34M | } |
69 | 10.7k | } |
70 | | |
71 | | void |
72 | | IndexedStyleSheets::ReindexOnNameChange(const SfxStyleSheetBase& style, const OUString& rOldName, const OUString& rNewName) |
73 | 558 | { |
74 | 558 | std::pair<MapType::const_iterator, MapType::const_iterator> range = mPositionsByName.equal_range(rOldName); |
75 | 558 | for (MapType::const_iterator it = range.first; it != range.second; ++it) |
76 | 0 | { |
77 | 0 | if (mStyleSheets[it->second].get() == &style) |
78 | 0 | { |
79 | 0 | unsigned nPos = it->second; |
80 | 0 | mPositionsByName.erase(it); |
81 | 0 | mPositionsByName.insert(std::make_pair(rNewName, nPos)); |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | } |
85 | 558 | } |
86 | | |
87 | | void |
88 | | IndexedStyleSheets::AddStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) |
89 | 784k | { |
90 | 784k | if (!HasStyleSheet(style)) { |
91 | 784k | mStyleSheets.push_back(style); |
92 | | // since we just added an element to the vector, we can safely do -1 as it will always be >= 1 |
93 | 784k | Register(*style, mStyleSheets.size()-1); |
94 | 784k | } |
95 | 784k | } |
96 | | |
97 | | bool |
98 | | IndexedStyleSheets::RemoveStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) |
99 | 0 | { |
100 | 0 | std::pair<MapType::const_iterator, MapType::const_iterator> range = mPositionsByName.equal_range(style->GetName()); |
101 | 0 | for (MapType::const_iterator it = range.first; it != range.second; ++it) |
102 | 0 | { |
103 | 0 | sal_Int32 pos = it->second; |
104 | 0 | if (mStyleSheets.at(pos) == style) |
105 | 0 | { |
106 | 0 | mStyleSheets.erase(mStyleSheets.begin() + pos); |
107 | 0 | Reindex(); |
108 | 0 | return true; |
109 | 0 | } |
110 | 0 | } |
111 | 0 | return false; |
112 | 0 | } |
113 | | |
114 | | std::vector<sal_Int32> IndexedStyleSheets::FindPositionsByName(const OUString& name) const |
115 | 0 | { |
116 | 0 | std::vector<sal_Int32> r; |
117 | 0 | std::pair<MapType::const_iterator, MapType::const_iterator> range = mPositionsByName.equal_range(name); |
118 | 0 | for (MapType::const_iterator it = range.first; it != range.second; ++it) { |
119 | 0 | r.push_back(it->second); |
120 | 0 | } |
121 | 0 | return r; |
122 | 0 | } |
123 | | |
124 | | std::vector<sal_Int32> IndexedStyleSheets::FindPositionsByNameAndPredicate(const OUString& name, |
125 | | StyleSheetPredicate& predicate, SearchBehavior behavior) const |
126 | 9.23M | { |
127 | 9.23M | std::vector<sal_Int32> r; |
128 | 9.23M | auto range = mPositionsByName.equal_range(name); |
129 | 9.88M | for (auto it = range.first; it != range.second; ++it) { |
130 | 5.89M | sal_Int32 pos = it->second; |
131 | 5.89M | SfxStyleSheetBase *ssheet = mStyleSheets.at(pos).get(); |
132 | 5.89M | if (predicate.Check(*ssheet)) { |
133 | 5.24M | r.push_back(pos); |
134 | 5.24M | if (behavior == SearchBehavior::ReturnFirst) { |
135 | 5.24M | break; |
136 | 5.24M | } |
137 | 5.24M | } |
138 | 5.89M | } |
139 | 9.23M | return r; |
140 | 9.23M | } |
141 | | |
142 | | |
143 | | sal_Int32 |
144 | | IndexedStyleSheets::GetNumberOfStyleSheetsWithPredicate(StyleSheetPredicate& predicate) const |
145 | 0 | { |
146 | 0 | return std::count_if(mStyleSheets.begin(), mStyleSheets.end(), |
147 | 0 | [&predicate](const rtl::Reference<SfxStyleSheetBase>& rxStyleSheet) { |
148 | 0 | const SfxStyleSheetBase *ssheet = rxStyleSheet.get(); |
149 | 0 | return predicate.Check(*ssheet); |
150 | 0 | }); |
151 | 0 | } |
152 | | |
153 | | std::pair<SfxStyleSheetBase*, sal_Int32> |
154 | | IndexedStyleSheets::GetNthStyleSheetThatMatchesPredicate( |
155 | | sal_Int32 n, |
156 | | StyleSheetPredicate& predicate, |
157 | | sal_Int32 startAt) |
158 | 0 | { |
159 | 0 | SfxStyleSheetBase* retval = nullptr; |
160 | 0 | sal_Int32 matching = 0; |
161 | 0 | VectorType::const_iterator it = mStyleSheets.begin()+startAt; |
162 | 0 | for (; it != mStyleSheets.end(); ++it) { |
163 | 0 | SfxStyleSheetBase *ssheet = it->get(); |
164 | 0 | if (predicate.Check(*ssheet)) { |
165 | 0 | if (matching == n) { |
166 | 0 | retval = it->get(); |
167 | 0 | break; |
168 | 0 | } |
169 | 0 | ++matching; |
170 | 0 | } |
171 | 0 | } |
172 | 0 | return { retval, std::distance(mStyleSheets.cbegin(), it) }; |
173 | 0 | } |
174 | | |
175 | | sal_Int32 IndexedStyleSheets::FindStyleSheetPosition(const SfxStyleSheetBase& style) const |
176 | 0 | { |
177 | 0 | VectorType::const_iterator it = std::find(mStyleSheets.begin(), mStyleSheets.end(), &style); |
178 | 0 | if (it == mStyleSheets.end()) { |
179 | 0 | throw std::runtime_error("IndexedStyleSheets::FindStylePosition Looked for style not in index"); |
180 | 0 | } |
181 | 0 | return std::distance(mStyleSheets.begin(), it); |
182 | 0 | } |
183 | | |
184 | | void |
185 | | IndexedStyleSheets::Clear(StyleSheetDisposer& disposer) |
186 | 302k | { |
187 | 782k | for (auto& rxStyleSheet : mStyleSheets) { |
188 | 782k | disposer.Dispose(rxStyleSheet); |
189 | | |
190 | | // tdf#161729 clear style sheets in same order as they were added |
191 | | // std::vector::clear() appears to delete elements in the |
192 | | // reverse order added. In the case of tdf#161729, a style |
193 | | // sheet's SfxItemSet can have a parent SfxItemSet and that |
194 | | // parent is the SfxItemSet for a style sheet added later. |
195 | | // Deleting from the end of the vector deletes a style sheet |
196 | | // and its SfxItemSet. If the now deleted SfxItemSet is a |
197 | | // parent SfxItemSet of a style sheet that was added earlier, |
198 | | // the style sheet added earlier will now have an SfxItemSet |
199 | | // with its parent set to an already deleted pointer. And so |
200 | | // a crash will occur when that earlier style sheet is deleted. |
201 | 782k | rxStyleSheet.clear(); |
202 | 782k | } |
203 | 302k | mStyleSheets.clear(); |
204 | 302k | mPositionsByName.clear(); |
205 | 302k | } |
206 | | |
207 | | IndexedStyleSheets::~IndexedStyleSheets() |
208 | 287k | { |
209 | 287k | } |
210 | | |
211 | | bool |
212 | | IndexedStyleSheets::HasStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) const |
213 | 784k | { |
214 | 784k | std::pair<MapType::const_iterator, MapType::const_iterator> range = mPositionsByName.equal_range(style->GetName()); |
215 | 862k | for (MapType::const_iterator it = range.first; it != range.second; ++it) |
216 | 77.3k | { |
217 | 77.3k | if (mStyleSheets.at(it->second) == style) |
218 | 0 | return true; |
219 | 77.3k | } |
220 | 784k | return false; |
221 | 784k | } |
222 | | |
223 | | SfxStyleSheetBase* |
224 | | IndexedStyleSheets::GetStyleSheetByPosition(sal_Int32 pos) |
225 | 5.24M | { |
226 | 5.24M | if( pos < static_cast<sal_Int32>(mStyleSheets.size()) ) |
227 | 5.24M | return mStyleSheets.at(pos).get(); |
228 | 0 | return nullptr; |
229 | 5.24M | } |
230 | | |
231 | | void |
232 | | IndexedStyleSheets::ApplyToAllStyleSheets(StyleSheetCallback& callback) const |
233 | 0 | { |
234 | 0 | for (const auto& rxStyleSheet : mStyleSheets) { |
235 | 0 | callback.DoIt(*rxStyleSheet); |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | std::vector<sal_Int32> |
240 | | IndexedStyleSheets::FindPositionsByPredicate(StyleSheetPredicate& predicate) const |
241 | 0 | { |
242 | 0 | std::vector<sal_Int32> r; |
243 | 0 | for (VectorType::const_iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { |
244 | 0 | if (predicate.Check(**it)) { |
245 | 0 | r.push_back(std::distance(mStyleSheets.begin(), it)); |
246 | 0 | } |
247 | 0 | } |
248 | 0 | return r; |
249 | 0 | } |
250 | | |
251 | | const std::vector<SfxStyleSheetBase*>& |
252 | | IndexedStyleSheets::GetStyleSheetsByFamily(SfxStyleFamily e) const |
253 | 15.6M | { |
254 | 15.6M | size_t position = family_to_index(e); |
255 | 15.6M | return mStyleSheetsByFamily.at(position); |
256 | 15.6M | } |
257 | | |
258 | | } /* namespace svl */ |
259 | | |
260 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |