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