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