annotate widgets/SubdividingMenu.cpp @ 427:1304dbe4542e

* Support importing features from RDF whose times are intervals rather than only instants; import them into region or note models. Sadly this makes RDF import much, much slower, because we need to work around Rasqal's single-OPTIONAL limitation by repeatedly querying each feature for time and range. * Add segmentation view to region layer, and display label texts
author Chris Cannam
date Tue, 07 Oct 2008 12:42:17 +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