annotate widgets/SubdividingMenu.cpp @ 960:6f97f5149cb3

Display note name derived from value, when hovering over time-value feature if the scale unit is Hz
author Chris Cannam
date Tue, 12 May 2015 14:25:00 +0100
parents 4a578a360011
children edfc38ade098
rev   line source
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