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