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