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