Mercurial > hg > svgui
comparison widgets/SubdividingMenu.cpp @ 1349:615eb28768ca zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 01 Oct 2018 15:48:20 +0100 |
parents | edfc38ade098 |
children | 53fe33b00770 |
comparison
equal
deleted
inserted
replaced
1346:4c28e3302045 | 1349:615eb28768ca |
---|---|
20 #include "base/Debug.h" | 20 #include "base/Debug.h" |
21 | 21 |
22 using std::set; | 22 using std::set; |
23 using std::map; | 23 using std::map; |
24 | 24 |
25 //#define DEBUG_SUBDIVIDING_MENU 1 | |
26 | |
25 SubdividingMenu::SubdividingMenu(int lowerLimit, int upperLimit, | 27 SubdividingMenu::SubdividingMenu(int lowerLimit, int upperLimit, |
26 QWidget *parent) : | 28 QWidget *parent) : |
27 QMenu(parent), | 29 QMenu(parent), |
28 m_lowerLimit(lowerLimit ? lowerLimit : 14), | 30 m_lowerLimit(lowerLimit ? lowerLimit : 14), |
29 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), | 31 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), |
30 m_entriesSet(false) | 32 m_entriesSet(false) |
31 { | 33 { |
34 #ifdef DEBUG_SUBDIVIDING_MENU | |
35 cerr << "SubdividingMenu: constructed without title" << endl; | |
36 #endif | |
32 } | 37 } |
33 | 38 |
34 SubdividingMenu::SubdividingMenu(const QString &title, int lowerLimit, | 39 SubdividingMenu::SubdividingMenu(const QString &title, int lowerLimit, |
35 int upperLimit, QWidget *parent) : | 40 int upperLimit, QWidget *parent) : |
36 QMenu(title, parent), | 41 QMenu(title, parent), |
37 m_lowerLimit(lowerLimit ? lowerLimit : 14), | 42 m_lowerLimit(lowerLimit ? lowerLimit : 14), |
38 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), | 43 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), |
39 m_entriesSet(false) | 44 m_entriesSet(false) |
40 { | 45 { |
46 #ifdef DEBUG_SUBDIVIDING_MENU | |
47 cerr << "SubdividingMenu: constructed with title \"" | |
48 << title << "\"" << endl; | |
49 #endif | |
41 } | 50 } |
42 | 51 |
43 SubdividingMenu::~SubdividingMenu() | 52 SubdividingMenu::~SubdividingMenu() |
44 { | 53 { |
45 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin(); | 54 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin(); |
51 void | 60 void |
52 SubdividingMenu::setEntries(const std::set<QString> &entries) | 61 SubdividingMenu::setEntries(const std::set<QString> &entries) |
53 { | 62 { |
54 m_entriesSet = true; | 63 m_entriesSet = true; |
55 | 64 |
65 #ifdef DEBUG_SUBDIVIDING_MENU | |
66 cerr << "SubdividingMenu::setEntries(" << title() << "): " | |
67 << entries.size() << " entries" << endl; | |
68 #endif | |
69 | |
56 int total = int(entries.size()); | 70 int total = int(entries.size()); |
57 | 71 |
58 if (total < m_upperLimit) return; | 72 if (total < m_upperLimit) return; |
59 | 73 |
60 int count = 0; | 74 int count = 0; |
63 | 77 |
64 QString firstNameInChunk; | 78 QString firstNameInChunk; |
65 QChar firstInitialInChunk; | 79 QChar firstInitialInChunk; |
66 bool discriminateStartInitial = false; | 80 bool discriminateStartInitial = false; |
67 | 81 |
68 for (set<QString>::const_iterator j = entries.begin(); | 82 // Re-sort using locale-aware comparator |
69 j != entries.end(); | 83 |
70 ++j) { | 84 auto comparator = [](QString s1, QString s2) -> bool { |
71 | 85 return QString::localeAwareCompare(s1, s2) < 0; |
72 // SVDEBUG << "SubdividingMenu::setEntries: j -> " << j->toStdString() << endl; | 86 }; |
87 | |
88 set<QString, typeof(comparator)> sortedEntries(comparator); | |
89 sortedEntries.insert(entries.begin(), entries.end()); | |
90 | |
91 for (auto j = sortedEntries.begin(); j != sortedEntries.end(); ++j) { | |
92 | |
93 #ifdef DEBUG_SUBDIVIDING_MENU | |
94 cerr << "SubdividingMenu::setEntries: entry is: " << j->toStdString() << endl; | |
95 #endif | |
73 | 96 |
74 m_nameToChunkMenuMap[*j] = chunkMenu; | 97 m_nameToChunkMenuMap[*j] = chunkMenu; |
75 | 98 |
76 set<QString>::iterator k = j; | 99 auto k = j; |
77 ++k; | 100 ++k; |
78 | 101 |
79 QChar initial = (*j)[0]; | 102 QChar initial = (*j)[0].toUpper(); |
80 | 103 |
81 if (count == 0) { | 104 if (count == 0) { |
82 firstNameInChunk = *j; | 105 firstNameInChunk = *j; |
83 firstInitialInChunk = initial; | 106 firstInitialInChunk = initial; |
107 #ifdef DEBUG_SUBDIVIDING_MENU | |
108 cerr << "starting new chunk at initial " << initial << endl; | |
109 #endif | |
84 } | 110 } |
85 | 111 |
86 // cerr << "count = "<< count << ", upper limit = " << m_upperLimit << endl; | 112 #ifdef DEBUG_SUBDIVIDING_MENU |
87 | 113 cerr << "count = "<< count << ", upper limit = " << m_upperLimit << endl; |
88 bool lastInChunk = (k == entries.end() || | 114 #endif |
115 | |
116 bool lastInChunk = (k == sortedEntries.end() || | |
89 (count >= m_lowerLimit-1 && | 117 (count >= m_lowerLimit-1 && |
90 (count == m_upperLimit || | 118 (count == m_upperLimit || |
91 (*k)[0] != initial))); | 119 (*k)[0].toUpper() != initial))); |
92 | 120 |
93 ++count; | 121 ++count; |
94 | 122 |
95 if (lastInChunk) { | 123 if (lastInChunk) { |
96 | 124 |
97 bool discriminateEndInitial = (k != entries.end() && | 125 bool discriminateEndInitial = (k != sortedEntries.end() && |
98 (*k)[0] == initial); | 126 (*k)[0].toUpper() == initial); |
99 | 127 |
100 bool initialsEqual = (firstInitialInChunk == initial); | 128 bool initialsEqual = (firstInitialInChunk == initial); |
101 | 129 |
102 QString from = QString("%1").arg(firstInitialInChunk); | 130 QString from = QString("%1").arg(firstInitialInChunk); |
103 if (discriminateStartInitial || | 131 if (discriminateStartInitial || |
134 | 162 |
135 void | 163 void |
136 SubdividingMenu::entriesAdded() | 164 SubdividingMenu::entriesAdded() |
137 { | 165 { |
138 if (m_entriesSet) { | 166 if (m_entriesSet) { |
139 cerr << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << endl; | 167 SVCERR << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << endl; |
140 return; | 168 return; |
141 } | 169 } |
142 | 170 |
143 set<QString> entries; | 171 set<QString> entries; |
144 for (map<QString, QObject *>::const_iterator i = m_pendingEntries.begin(); | 172 for (auto i: m_pendingEntries) { |
145 i != m_pendingEntries.end(); ++i) { | 173 entries.insert(i.first); |
146 entries.insert(i->first); | 174 } |
147 } | |
148 | |
149 setEntries(entries); | 175 setEntries(entries); |
150 | 176 |
151 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin(); | 177 // Re-sort using locale-aware comparator (setEntries will do this |
152 i != m_pendingEntries.end(); ++i) { | 178 // again, for the set passed to it, but we need the same sorting |
153 | 179 // for the subsequent loop in this function as well) |
154 QMenu *menu = dynamic_cast<QMenu *>(i->second); | 180 auto comparator = [](QString s1, QString s2) -> bool { |
181 return QString::localeAwareCompare(s1, s2) < 0; | |
182 }; | |
183 set<QString, typeof(comparator)> sortedEntries(comparator); | |
184 for (auto i: m_pendingEntries) { | |
185 sortedEntries.insert(i.first); | |
186 } | |
187 | |
188 for (QString entry: sortedEntries) { | |
189 | |
190 QObject *obj = m_pendingEntries[entry]; | |
191 | |
192 QMenu *menu = dynamic_cast<QMenu *>(obj); | |
155 if (menu) { | 193 if (menu) { |
156 addMenu(i->first, menu); | 194 addMenu(entry, menu); |
157 continue; | 195 continue; |
158 } | 196 } |
159 | 197 |
160 QAction *action = dynamic_cast<QAction *>(i->second); | 198 QAction *action = dynamic_cast<QAction *>(obj); |
161 if (action) { | 199 if (action) { |
162 addAction(i->first, action); | 200 addAction(entry, action); |
163 continue; | 201 continue; |
164 } | 202 } |
165 } | 203 } |
166 | 204 |
167 m_pendingEntries.clear(); | 205 m_pendingEntries.clear(); |
176 m_pendingEntries[name] = action; | 214 m_pendingEntries[name] = action; |
177 return; | 215 return; |
178 } | 216 } |
179 | 217 |
180 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 218 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
181 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 219 #ifdef DEBUG_SUBDIVIDING_MENU |
220 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
221 #endif | |
182 QMenu::addAction(action); | 222 QMenu::addAction(action); |
183 return; | 223 return; |
184 } | 224 } |
185 | 225 |
186 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 226 #ifdef DEBUG_SUBDIVIDING_MENU |
227 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
228 #endif | |
187 m_nameToChunkMenuMap[name]->addAction(action); | 229 m_nameToChunkMenuMap[name]->addAction(action); |
188 } | 230 } |
189 | 231 |
190 QAction * | 232 QAction * |
191 SubdividingMenu::addAction(const QString &name) | 233 SubdividingMenu::addAction(const QString &name) |
195 m_pendingEntries[name] = action; | 237 m_pendingEntries[name] = action; |
196 return action; | 238 return action; |
197 } | 239 } |
198 | 240 |
199 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 241 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
200 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 242 #ifdef DEBUG_SUBDIVIDING_MENU |
243 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
244 #endif | |
201 return QMenu::addAction(name); | 245 return QMenu::addAction(name); |
202 } | 246 } |
203 | 247 |
204 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 248 #ifdef DEBUG_SUBDIVIDING_MENU |
249 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
250 #endif | |
205 return m_nameToChunkMenuMap[name]->addAction(name); | 251 return m_nameToChunkMenuMap[name]->addAction(name); |
206 } | 252 } |
207 | 253 |
208 void | 254 void |
209 SubdividingMenu::addAction(const QString &name, QAction *action) | 255 SubdividingMenu::addAction(const QString &name, QAction *action) |
212 m_pendingEntries[name] = action; | 258 m_pendingEntries[name] = action; |
213 return; | 259 return; |
214 } | 260 } |
215 | 261 |
216 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 262 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
217 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 263 #ifdef DEBUG_SUBDIVIDING_MENU |
264 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
265 #endif | |
218 QMenu::addAction(action); | 266 QMenu::addAction(action); |
219 return; | 267 return; |
220 } | 268 } |
221 | 269 |
222 // SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 270 #ifdef DEBUG_SUBDIVIDING_MENU |
271 cerr << "SubdividingMenu::addAction(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
272 #endif | |
223 m_nameToChunkMenuMap[name]->addAction(action); | 273 m_nameToChunkMenuMap[name]->addAction(action); |
224 } | 274 } |
225 | 275 |
226 void | 276 void |
227 SubdividingMenu::addMenu(QMenu *menu) | 277 SubdividingMenu::addMenu(QMenu *menu) |
232 m_pendingEntries[name] = menu; | 282 m_pendingEntries[name] = menu; |
233 return; | 283 return; |
234 } | 284 } |
235 | 285 |
236 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 286 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
237 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 287 #ifdef DEBUG_SUBDIVIDING_MENU |
288 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
289 #endif | |
238 QMenu::addMenu(menu); | 290 QMenu::addMenu(menu); |
239 return; | 291 return; |
240 } | 292 } |
241 | 293 |
242 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 294 #ifdef DEBUG_SUBDIVIDING_MENU |
295 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
296 #endif | |
243 m_nameToChunkMenuMap[name]->addMenu(menu); | 297 m_nameToChunkMenuMap[name]->addMenu(menu); |
244 } | 298 } |
245 | 299 |
246 QMenu * | 300 QMenu * |
247 SubdividingMenu::addMenu(const QString &name) | 301 SubdividingMenu::addMenu(const QString &name) |
252 m_pendingEntries[name] = menu; | 306 m_pendingEntries[name] = menu; |
253 return menu; | 307 return menu; |
254 } | 308 } |
255 | 309 |
256 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 310 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
257 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 311 #ifdef DEBUG_SUBDIVIDING_MENU |
312 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
313 #endif | |
258 return QMenu::addMenu(name); | 314 return QMenu::addMenu(name); |
259 } | 315 } |
260 | 316 |
261 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 317 #ifdef DEBUG_SUBDIVIDING_MENU |
318 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
319 #endif | |
262 return m_nameToChunkMenuMap[name]->addMenu(name); | 320 return m_nameToChunkMenuMap[name]->addMenu(name); |
263 } | 321 } |
264 | 322 |
265 void | 323 void |
266 SubdividingMenu::addMenu(const QString &name, QMenu *menu) | 324 SubdividingMenu::addMenu(const QString &name, QMenu *menu) |
269 m_pendingEntries[name] = menu; | 327 m_pendingEntries[name] = menu; |
270 return; | 328 return; |
271 } | 329 } |
272 | 330 |
273 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { | 331 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { |
274 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl; | 332 #ifdef DEBUG_SUBDIVIDING_MENU |
333 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): not found in name-to-chunk map, adding to main menu" << endl; | |
334 #endif | |
275 QMenu::addMenu(menu); | 335 QMenu::addMenu(menu); |
276 return; | 336 return; |
277 } | 337 } |
278 | 338 |
279 // SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | 339 #ifdef DEBUG_SUBDIVIDING_MENU |
340 cerr << "SubdividingMenu::addMenu(" << title() << " | " << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl; | |
341 #endif | |
280 m_nameToChunkMenuMap[name]->addMenu(menu); | 342 m_nameToChunkMenuMap[name]->addMenu(menu); |
281 } | 343 } |
282 | 344 |