lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include "SubdividingMenu.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: using std::set; lbajardsilogic@0: using std::map; lbajardsilogic@0: lbajardsilogic@0: SubdividingMenu::SubdividingMenu(size_t lowerLimit, size_t upperLimit, lbajardsilogic@0: QWidget *parent) : lbajardsilogic@0: QMenu(parent), lbajardsilogic@0: m_lowerLimit(lowerLimit ? lowerLimit : 14), lbajardsilogic@0: m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), lbajardsilogic@0: m_entriesSet(false) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: SubdividingMenu::SubdividingMenu(const QString &title, size_t lowerLimit, lbajardsilogic@0: size_t upperLimit, QWidget *parent) : lbajardsilogic@0: QMenu(title, parent), lbajardsilogic@0: m_lowerLimit(lowerLimit ? lowerLimit : 14), lbajardsilogic@0: m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2), lbajardsilogic@0: m_entriesSet(false) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: SubdividingMenu::~SubdividingMenu() lbajardsilogic@0: { lbajardsilogic@0: for (map::iterator i = m_pendingEntries.begin(); lbajardsilogic@0: i != m_pendingEntries.end(); ++i) { lbajardsilogic@0: delete i->second; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::setEntries(const std::set &entries) lbajardsilogic@0: { lbajardsilogic@0: m_entriesSet = true; lbajardsilogic@0: lbajardsilogic@0: size_t total = entries.size(); lbajardsilogic@0: lbajardsilogic@0: if (total < m_upperLimit) return; lbajardsilogic@0: lbajardsilogic@0: size_t count = 0; lbajardsilogic@0: QMenu *chunkMenu = new QMenu(); lbajardsilogic@0: chunkMenu->setTearOffEnabled(isTearOffEnabled()); lbajardsilogic@0: lbajardsilogic@0: QString firstNameInChunk; lbajardsilogic@0: QChar firstInitialInChunk; lbajardsilogic@0: bool discriminateStartInitial = false; lbajardsilogic@0: lbajardsilogic@0: for (set::const_iterator j = entries.begin(); lbajardsilogic@0: j != entries.end(); lbajardsilogic@0: ++j) { lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::setEntries: j -> " << j->toStdString() << std::endl; lbajardsilogic@0: lbajardsilogic@0: m_nameToChunkMenuMap[*j] = chunkMenu; lbajardsilogic@0: lbajardsilogic@0: set::const_iterator k = j; lbajardsilogic@0: ++k; lbajardsilogic@0: lbajardsilogic@0: QChar initial = (*j)[0]; lbajardsilogic@0: lbajardsilogic@0: if (count == 0) { lbajardsilogic@0: firstNameInChunk = *j; lbajardsilogic@0: firstInitialInChunk = initial; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "count = "<< count << ", upper limit = " << m_upperLimit << std::endl; lbajardsilogic@0: lbajardsilogic@0: bool lastInChunk = (k == entries.end() || lbajardsilogic@0: (count >= m_lowerLimit-1 && lbajardsilogic@0: (count == m_upperLimit || lbajardsilogic@0: (*k)[0] != initial))); lbajardsilogic@0: lbajardsilogic@0: ++count; lbajardsilogic@0: lbajardsilogic@0: if (lastInChunk) { lbajardsilogic@0: lbajardsilogic@0: bool discriminateEndInitial = (k != entries.end() && lbajardsilogic@0: (*k)[0] == initial); lbajardsilogic@0: lbajardsilogic@0: bool initialsEqual = (firstInitialInChunk == initial); lbajardsilogic@0: lbajardsilogic@0: QString from = QString("%1").arg(firstInitialInChunk); lbajardsilogic@0: if (discriminateStartInitial || lbajardsilogic@0: (discriminateEndInitial && initialsEqual)) { lbajardsilogic@0: from = firstNameInChunk.left(3); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString to = QString("%1").arg(initial); lbajardsilogic@0: if (discriminateEndInitial || lbajardsilogic@0: (discriminateStartInitial && initialsEqual)) { lbajardsilogic@0: to = j->left(3); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString menuText; lbajardsilogic@0: lbajardsilogic@0: if (from == to) menuText = from; lbajardsilogic@0: else menuText = tr("%1 - %2").arg(from).arg(to); lbajardsilogic@0: lbajardsilogic@0: discriminateStartInitial = discriminateEndInitial; lbajardsilogic@0: lbajardsilogic@0: chunkMenu->setTitle(menuText); lbajardsilogic@0: lbajardsilogic@0: QMenu::addMenu(chunkMenu); lbajardsilogic@0: lbajardsilogic@0: chunkMenu = new QMenu(); lbajardsilogic@0: chunkMenu->setTearOffEnabled(isTearOffEnabled()); lbajardsilogic@0: lbajardsilogic@0: count = 0; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (count == 0) delete chunkMenu; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::entriesAdded() lbajardsilogic@0: { lbajardsilogic@0: if (m_entriesSet) { lbajardsilogic@0: std::cerr << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: set entries; lbajardsilogic@0: for (map::const_iterator i = m_pendingEntries.begin(); lbajardsilogic@0: i != m_pendingEntries.end(); ++i) { lbajardsilogic@0: entries.insert(i->first); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: setEntries(entries); lbajardsilogic@0: lbajardsilogic@0: for (map::iterator i = m_pendingEntries.begin(); lbajardsilogic@0: i != m_pendingEntries.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QMenu *menu = dynamic_cast(i->second); lbajardsilogic@0: if (menu) { lbajardsilogic@0: addMenu(i->first, menu); lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QAction *action = dynamic_cast(i->second); lbajardsilogic@0: if (action) { lbajardsilogic@0: addAction(i->first, action); lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_pendingEntries.clear(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::addAction(QAction *action) lbajardsilogic@0: { lbajardsilogic@0: QString name = action->text(); lbajardsilogic@0: lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: m_pendingEntries[name] = action; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: QMenu::addAction(action); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: m_nameToChunkMenuMap[name]->addAction(action); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QAction * lbajardsilogic@0: SubdividingMenu::addAction(const QString &name) lbajardsilogic@0: { lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: QAction *action = new QAction(name, this); lbajardsilogic@0: m_pendingEntries[name] = action; lbajardsilogic@0: return action; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: return QMenu::addAction(name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: return m_nameToChunkMenuMap[name]->addAction(name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::addAction(const QString &name, QAction *action) lbajardsilogic@0: { lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: m_pendingEntries[name] = action; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: QMenu::addAction(action); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addAction(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: m_nameToChunkMenuMap[name]->addAction(action); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::addMenu(QMenu *menu) lbajardsilogic@0: { lbajardsilogic@0: QString name = menu->title(); lbajardsilogic@0: lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: m_pendingEntries[name] = menu; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: QMenu::addMenu(menu); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: m_nameToChunkMenuMap[name]->addMenu(menu); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QMenu * lbajardsilogic@0: SubdividingMenu::addMenu(const QString &name) lbajardsilogic@0: { lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: QMenu *menu = new QMenu(name, this); lbajardsilogic@0: menu->setTearOffEnabled(isTearOffEnabled()); lbajardsilogic@0: m_pendingEntries[name] = menu; lbajardsilogic@0: return menu; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: return QMenu::addMenu(name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: return m_nameToChunkMenuMap[name]->addMenu(name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SubdividingMenu::addMenu(const QString &name, QMenu *menu) lbajardsilogic@0: { lbajardsilogic@0: if (!m_entriesSet) { lbajardsilogic@0: m_pendingEntries[name] = menu; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) { lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): not found in name-to-chunk map, adding to main menu" << std::endl; lbajardsilogic@0: QMenu::addMenu(menu); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "SubdividingMenu::addMenu(" << name.toStdString() << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title().toStdString() << std::endl; lbajardsilogic@0: m_nameToChunkMenuMap[name]->addMenu(menu); lbajardsilogic@0: } lbajardsilogic@0: