Chris@151
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@151
|
2
|
Chris@151
|
3 /*
|
Chris@151
|
4 Sonic Visualiser
|
Chris@151
|
5 An audio file viewer and annotation editor.
|
Chris@151
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@151
|
7
|
Chris@151
|
8 This program is free software; you can redistribute it and/or
|
Chris@151
|
9 modify it under the terms of the GNU General Public License as
|
Chris@151
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@151
|
11 License, or (at your option) any later version. See the file
|
Chris@151
|
12 COPYING included with this distribution for more information.
|
Chris@151
|
13 */
|
Chris@151
|
14
|
Chris@151
|
15 #include "SubdividingMenu.h"
|
Chris@151
|
16
|
Chris@151
|
17 #include <iostream>
|
Chris@151
|
18
|
Chris@151
|
19 using std::set;
|
Chris@151
|
20 using std::map;
|
Chris@151
|
21
|
Chris@152
|
22 SubdividingMenu::SubdividingMenu(size_t lowerLimit, size_t upperLimit,
|
Chris@152
|
23 QWidget *parent) :
|
Chris@152
|
24 QMenu(parent),
|
Chris@152
|
25 m_lowerLimit(lowerLimit ? lowerLimit : 14),
|
Chris@152
|
26 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
|
Chris@152
|
27 m_entriesSet(false)
|
Chris@151
|
28 {
|
Chris@151
|
29 }
|
Chris@151
|
30
|
Chris@152
|
31 SubdividingMenu::SubdividingMenu(const QString &title, size_t lowerLimit,
|
Chris@152
|
32 size_t upperLimit, QWidget *parent) :
|
Chris@152
|
33 QMenu(title, parent),
|
Chris@152
|
34 m_lowerLimit(lowerLimit ? lowerLimit : 14),
|
Chris@152
|
35 m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
|
Chris@152
|
36 m_entriesSet(false)
|
Chris@151
|
37 {
|
Chris@151
|
38 }
|
Chris@151
|
39
|
Chris@151
|
40 SubdividingMenu::~SubdividingMenu()
|
Chris@151
|
41 {
|
Chris@152
|
42 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
|
Chris@152
|
43 i != m_pendingEntries.end(); ++i) {
|
Chris@152
|
44 delete i->second;
|
Chris@152
|
45 }
|
Chris@151
|
46 }
|
Chris@151
|
47
|
Chris@151
|
48 void
|
Chris@151
|
49 SubdividingMenu::setEntries(const std::set<QString> &entries)
|
Chris@151
|
50 {
|
Chris@152
|
51 m_entriesSet = true;
|
Chris@152
|
52
|
Chris@151
|
53 size_t total = entries.size();
|
Chris@151
|
54
|
Chris@152
|
55 if (total < m_upperLimit) return;
|
Chris@151
|
56
|
Chris@151
|
57 size_t count = 0;
|
Chris@151
|
58 QMenu *chunkMenu = new QMenu();
|
Chris@151
|
59
|
Chris@151
|
60 QString firstNameInChunk;
|
Chris@151
|
61 QChar firstInitialInChunk;
|
Chris@151
|
62 bool discriminateStartInitial = false;
|
Chris@151
|
63
|
Chris@151
|
64 for (set<QString>::const_iterator j = entries.begin();
|
Chris@151
|
65 j != entries.end();
|
Chris@151
|
66 ++j) {
|
Chris@151
|
67
|
Chris@152
|
68 // std::cerr << "SubdividingMenu::setEntries: j -> " << j->toStdString() << std::endl;
|
Chris@151
|
69
|
Chris@151
|
70 m_nameToChunkMenuMap[*j] = chunkMenu;
|
Chris@151
|
71
|
Chris@151
|
72 set<QString>::iterator k = j;
|
Chris@151
|
73 ++k;
|
Chris@151
|
74
|
Chris@151
|
75 QChar initial = (*j)[0];
|
Chris@151
|
76
|
Chris@151
|
77 if (count == 0) {
|
Chris@151
|
78 firstNameInChunk = *j;
|
Chris@151
|
79 firstInitialInChunk = initial;
|
Chris@151
|
80 }
|
Chris@151
|
81
|
Chris@152
|
82 // std::cerr << "count = "<< count << ", upper limit = " << m_upperLimit << std::endl;
|
Chris@152
|
83
|
Chris@151
|
84 bool lastInChunk = (k == entries.end() ||
|
Chris@152
|
85 (count >= m_lowerLimit-1 &&
|
Chris@152
|
86 (count == m_upperLimit ||
|
Chris@151
|
87 (*k)[0] != initial)));
|
Chris@151
|
88
|
Chris@151
|
89 ++count;
|
Chris@151
|
90
|
Chris@151
|
91 if (lastInChunk) {
|
Chris@151
|
92
|
Chris@151
|
93 bool discriminateEndInitial = (k != entries.end() &&
|
Chris@151
|
94 (*k)[0] == initial);
|
Chris@151
|
95
|
Chris@151
|
96 bool initialsEqual = (firstInitialInChunk == initial);
|
Chris@151
|
97
|
Chris@151
|
98 QString from = QString("%1").arg(firstInitialInChunk);
|
Chris@151
|
99 if (discriminateStartInitial ||
|
Chris@151
|
100 (discriminateEndInitial && initialsEqual)) {
|
Chris@151
|
101 from = firstNameInChunk.left(3);
|
Chris@151
|
102 }
|
Chris@151
|
103
|
Chris@151
|
104 QString to = QString("%1").arg(initial);
|
Chris@151
|
105 if (discriminateEndInitial ||
|
Chris@151
|
106 (discriminateStartInitial && initialsEqual)) {
|
Chris@151
|
107 to = j->left(3);
|
Chris@151
|
108 }
|
Chris@151
|
109
|
Chris@151
|
110 QString menuText;
|
Chris@151
|
111
|
Chris@151
|
112 if (from == to) menuText = from;
|
Chris@151
|
113 else menuText = tr("%1 - %2").arg(from).arg(to);
|
Chris@151
|
114
|
Chris@151
|
115 discriminateStartInitial = discriminateEndInitial;
|
Chris@151
|
116
|
Chris@151
|
117 chunkMenu->setTitle(menuText);
|
Chris@151
|
118
|
Chris@151
|
119 QMenu::addMenu(chunkMenu);
|
Chris@151
|
120
|
Chris@151
|
121 chunkMenu = new QMenu();
|
Chris@151
|
122
|
Chris@151
|
123 count = 0;
|
Chris@151
|
124 }
|
Chris@151
|
125 }
|
Chris@151
|
126
|
Chris@151
|
127 if (count == 0) delete chunkMenu;
|
Chris@151
|
128 }
|
Chris@151
|
129
|
Chris@151
|
130 void
|
Chris@152
|
131 SubdividingMenu::entriesAdded()
|
Chris@152
|
132 {
|
Chris@152
|
133 if (m_entriesSet) {
|
Chris@152
|
134 std::cerr << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << std::endl;
|
Chris@152
|
135 return;
|
Chris@152
|
136 }
|
Chris@152
|
137
|
Chris@152
|
138 set<QString> entries;
|
Chris@152
|
139 for (map<QString, QObject *>::const_iterator i = m_pendingEntries.begin();
|
Chris@152
|
140 i != m_pendingEntries.end(); ++i) {
|
Chris@152
|
141 entries.insert(i->first);
|
Chris@152
|
142 }
|
Chris@152
|
143
|
Chris@152
|
144 setEntries(entries);
|
Chris@152
|
145
|
Chris@152
|
146 for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
|
Chris@152
|
147 i != m_pendingEntries.end(); ++i) {
|
Chris@152
|
148
|
Chris@152
|
149 QMenu *menu = dynamic_cast<QMenu *>(i->second);
|
Chris@152
|
150 if (menu) {
|
Chris@152
|
151 addMenu(i->first, menu);
|
Chris@152
|
152 continue;
|
Chris@152
|
153 }
|
Chris@152
|
154
|
Chris@152
|
155 QAction *action = dynamic_cast<QAction *>(i->second);
|
Chris@152
|
156 if (action) {
|
Chris@152
|
157 addAction(i->first, action);
|
Chris@152
|
158 continue;
|
Chris@152
|
159 }
|
Chris@152
|
160 }
|
Chris@152
|
161
|
Chris@152
|
162 m_pendingEntries.clear();
|
Chris@152
|
163 }
|
Chris@152
|
164
|
Chris@152
|
165 void
|
Chris@151
|
166 SubdividingMenu::addAction(QAction *action)
|
Chris@151
|
167 {
|
Chris@151
|
168 QString name = action->text();
|
Chris@151
|
169
|
Chris@152
|
170 if (!m_entriesSet) {
|
Chris@152
|
171 m_pendingEntries[name] = action;
|
Chris@152
|
172 return;
|
Chris@152
|
173 }
|
Chris@152
|
174
|
Chris@151
|
175 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
176 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
177 QMenu::addAction(action);
|
Chris@151
|
178 return;
|
Chris@151
|
179 }
|
Chris@151
|
180
|
Chris@152
|
181 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
182 m_nameToChunkMenuMap[name]->addAction(action);
|
Chris@151
|
183 }
|
Chris@151
|
184
|
Chris@151
|
185 QAction *
|
Chris@151
|
186 SubdividingMenu::addAction(const QString &name)
|
Chris@151
|
187 {
|
Chris@152
|
188 if (!m_entriesSet) {
|
Chris@152
|
189 QAction *action = new QAction(name, this);
|
Chris@152
|
190 m_pendingEntries[name] = action;
|
Chris@152
|
191 return action;
|
Chris@152
|
192 }
|
Chris@152
|
193
|
Chris@151
|
194 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
195 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
196 return QMenu::addAction(name);
|
Chris@151
|
197 }
|
Chris@151
|
198
|
Chris@152
|
199 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
200 return m_nameToChunkMenuMap[name]->addAction(name);
|
Chris@151
|
201 }
|
Chris@151
|
202
|
Chris@151
|
203 void
|
Chris@151
|
204 SubdividingMenu::addAction(const QString &name, QAction *action)
|
Chris@151
|
205 {
|
Chris@152
|
206 if (!m_entriesSet) {
|
Chris@152
|
207 m_pendingEntries[name] = action;
|
Chris@152
|
208 return;
|
Chris@152
|
209 }
|
Chris@152
|
210
|
Chris@151
|
211 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
212 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
213 QMenu::addAction(action);
|
Chris@151
|
214 return;
|
Chris@151
|
215 }
|
Chris@151
|
216
|
Chris@152
|
217 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
218 m_nameToChunkMenuMap[name]->addAction(action);
|
Chris@151
|
219 }
|
Chris@151
|
220
|
Chris@151
|
221 void
|
Chris@151
|
222 SubdividingMenu::addMenu(QMenu *menu)
|
Chris@151
|
223 {
|
Chris@151
|
224 QString name = menu->title();
|
Chris@151
|
225
|
Chris@152
|
226 if (!m_entriesSet) {
|
Chris@152
|
227 m_pendingEntries[name] = menu;
|
Chris@152
|
228 return;
|
Chris@152
|
229 }
|
Chris@152
|
230
|
Chris@151
|
231 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
232 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
233 QMenu::addMenu(menu);
|
Chris@151
|
234 return;
|
Chris@151
|
235 }
|
Chris@151
|
236
|
Chris@152
|
237 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
238 m_nameToChunkMenuMap[name]->addMenu(menu);
|
Chris@151
|
239 }
|
Chris@151
|
240
|
Chris@151
|
241 QMenu *
|
Chris@151
|
242 SubdividingMenu::addMenu(const QString &name)
|
Chris@151
|
243 {
|
Chris@152
|
244 if (!m_entriesSet) {
|
Chris@152
|
245 QMenu *menu = new QMenu(name, this);
|
Chris@152
|
246 m_pendingEntries[name] = menu;
|
Chris@152
|
247 return menu;
|
Chris@152
|
248 }
|
Chris@152
|
249
|
Chris@151
|
250 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
251 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
252 return QMenu::addMenu(name);
|
Chris@151
|
253 }
|
Chris@151
|
254
|
Chris@152
|
255 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
256 return m_nameToChunkMenuMap[name]->addMenu(name);
|
Chris@151
|
257 }
|
Chris@151
|
258
|
Chris@151
|
259 void
|
Chris@151
|
260 SubdividingMenu::addMenu(const QString &name, QMenu *menu)
|
Chris@151
|
261 {
|
Chris@152
|
262 if (!m_entriesSet) {
|
Chris@152
|
263 m_pendingEntries[name] = menu;
|
Chris@152
|
264 return;
|
Chris@152
|
265 }
|
Chris@152
|
266
|
Chris@151
|
267 if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
|
Chris@152
|
268 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
|
Chris@151
|
269 QMenu::addMenu(menu);
|
Chris@151
|
270 return;
|
Chris@151
|
271 }
|
Chris@151
|
272
|
Chris@152
|
273 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
|
Chris@151
|
274 m_nameToChunkMenuMap[name]->addMenu(menu);
|
Chris@151
|
275 }
|
Chris@151
|
276
|