annotate widgets/SubdividingMenu.cpp @ 378:22b72f0f6a4e

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents 22c99c8aa1e0
children 1fe7951a61e8
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@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@152 70 // std::cerr << "SubdividingMenu::setEntries: j -> " << j->toStdString() << std::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@152 179 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 180 QMenu::addAction(action);
Chris@151 181 return;
Chris@151 182 }
Chris@151 183
Chris@152 184 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::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@152 198 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 199 return QMenu::addAction(name);
Chris@151 200 }
Chris@151 201
Chris@152 202 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::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@152 215 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 216 QMenu::addAction(action);
Chris@151 217 return;
Chris@151 218 }
Chris@151 219
Chris@152 220 // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::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@152 235 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 236 QMenu::addMenu(menu);
Chris@151 237 return;
Chris@151 238 }
Chris@151 239
Chris@152 240 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::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@152 255 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 256 return QMenu::addMenu(name);
Chris@151 257 }
Chris@151 258
Chris@152 259 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::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@152 272 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl;
Chris@151 273 QMenu::addMenu(menu);
Chris@151 274 return;
Chris@151 275 }
Chris@151 276
Chris@152 277 // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl;
Chris@151 278 m_nameToChunkMenuMap[name]->addMenu(menu);
Chris@151 279 }
Chris@151 280