svgui  1.9
SubdividingMenu.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "SubdividingMenu.h"
00017 
00018 #include <iostream>
00019 
00020 #include "base/Debug.h"
00021 
00022 using std::set;
00023 using std::map;
00024 
00025 SubdividingMenu::SubdividingMenu(int lowerLimit, int upperLimit,
00026                                  QWidget *parent) :
00027     QMenu(parent),
00028     m_lowerLimit(lowerLimit ? lowerLimit : 14),
00029     m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
00030     m_entriesSet(false)
00031 {
00032 }
00033 
00034 SubdividingMenu::SubdividingMenu(const QString &title, int lowerLimit,
00035                                  int upperLimit, QWidget *parent) :
00036     QMenu(title, parent),
00037     m_lowerLimit(lowerLimit ? lowerLimit : 14),
00038     m_upperLimit(upperLimit ? upperLimit : (m_lowerLimit * 5) / 2),
00039     m_entriesSet(false)
00040 {
00041 }
00042 
00043 SubdividingMenu::~SubdividingMenu()
00044 {
00045     for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
00046          i != m_pendingEntries.end(); ++i) {
00047         delete i->second;
00048     }
00049 }
00050 
00051 void
00052 SubdividingMenu::setEntries(const std::set<QString> &entries)
00053 {
00054     m_entriesSet = true;
00055 
00056     int total = entries.size();
00057         
00058     if (total < m_upperLimit) return;
00059 
00060     int count = 0;
00061     QMenu *chunkMenu = new QMenu();
00062     chunkMenu->setTearOffEnabled(isTearOffEnabled());
00063 
00064     QString firstNameInChunk;
00065     QChar firstInitialInChunk;
00066     bool discriminateStartInitial = false;
00067 
00068     for (set<QString>::const_iterator j = entries.begin();
00069          j != entries.end();
00070          ++j) {
00071 
00072 //        SVDEBUG << "SubdividingMenu::setEntries: j -> " << j->toStdString() << endl;
00073 
00074         m_nameToChunkMenuMap[*j] = chunkMenu;
00075 
00076         set<QString>::iterator k = j;
00077         ++k;
00078 
00079         QChar initial = (*j)[0];
00080 
00081         if (count == 0) {
00082             firstNameInChunk = *j;
00083             firstInitialInChunk = initial;
00084         }
00085 
00086 //        cerr << "count = "<< count << ", upper limit = " << m_upperLimit << endl;
00087 
00088         bool lastInChunk = (k == entries.end() ||
00089                             (count >= m_lowerLimit-1 &&
00090                              (count == m_upperLimit ||
00091                               (*k)[0] != initial)));
00092 
00093         ++count;
00094 
00095         if (lastInChunk) {
00096 
00097             bool discriminateEndInitial = (k != entries.end() &&
00098                                            (*k)[0] == initial);
00099 
00100             bool initialsEqual = (firstInitialInChunk == initial);
00101 
00102             QString from = QString("%1").arg(firstInitialInChunk);
00103             if (discriminateStartInitial ||
00104                 (discriminateEndInitial && initialsEqual)) {
00105                 from = firstNameInChunk.left(3);
00106             }
00107 
00108             QString to = QString("%1").arg(initial);
00109             if (discriminateEndInitial ||
00110                 (discriminateStartInitial && initialsEqual)) {
00111                 to = j->left(3);
00112             }
00113 
00114             QString menuText;
00115             
00116             if (from == to) menuText = from;
00117             else menuText = tr("%1 - %2").arg(from).arg(to);
00118             
00119             discriminateStartInitial = discriminateEndInitial;
00120 
00121             chunkMenu->setTitle(menuText);
00122                 
00123             QMenu::addMenu(chunkMenu);
00124             
00125             chunkMenu = new QMenu();
00126             chunkMenu->setTearOffEnabled(isTearOffEnabled());
00127             
00128             count = 0;
00129         }
00130     }
00131     
00132     if (count == 0) delete chunkMenu;
00133 }
00134 
00135 void
00136 SubdividingMenu::entriesAdded()
00137 {
00138     if (m_entriesSet) {
00139         cerr << "ERROR: SubdividingMenu::entriesAdded: setEntries was also called -- should use one mechanism or the other, but not both" << endl;
00140         return;
00141     }
00142     
00143     set<QString> entries;
00144     for (map<QString, QObject *>::const_iterator i = m_pendingEntries.begin();
00145          i != m_pendingEntries.end(); ++i) {
00146         entries.insert(i->first);
00147     }
00148     
00149     setEntries(entries);
00150 
00151     for (map<QString, QObject *>::iterator i = m_pendingEntries.begin();
00152          i != m_pendingEntries.end(); ++i) {
00153 
00154         QMenu *menu = dynamic_cast<QMenu *>(i->second);
00155         if (menu) {
00156             addMenu(i->first, menu);
00157             continue;
00158         }
00159 
00160         QAction *action = dynamic_cast<QAction *>(i->second);
00161         if (action) {
00162             addAction(i->first, action);
00163             continue;
00164         }
00165     }
00166 
00167     m_pendingEntries.clear();
00168 }
00169 
00170 void
00171 SubdividingMenu::addAction(QAction *action)
00172 {
00173     QString name = action->text();
00174 
00175     if (!m_entriesSet) {
00176         m_pendingEntries[name] = action;
00177         return;
00178     }
00179 
00180     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00181 //        SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00182         QMenu::addAction(action);
00183         return;
00184     }
00185 
00186 //    SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00187     m_nameToChunkMenuMap[name]->addAction(action);
00188 }
00189 
00190 QAction *
00191 SubdividingMenu::addAction(const QString &name)
00192 {
00193     if (!m_entriesSet) {
00194         QAction *action = new QAction(name, this);
00195         m_pendingEntries[name] = action;
00196         return action;
00197     }
00198 
00199     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00200 //        SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00201         return QMenu::addAction(name);
00202     }
00203 
00204 //    SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00205     return m_nameToChunkMenuMap[name]->addAction(name);
00206 }
00207 
00208 void
00209 SubdividingMenu::addAction(const QString &name, QAction *action)
00210 {
00211     if (!m_entriesSet) {
00212         m_pendingEntries[name] = action;
00213         return;
00214     }
00215 
00216     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00217 //        SVDEBUG << "SubdividingMenu::addAction(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00218         QMenu::addAction(action);
00219         return;
00220     }
00221 
00222 //    SVDEBUG << "SubdividingMenu::addAction(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00223     m_nameToChunkMenuMap[name]->addAction(action);
00224 }
00225 
00226 void
00227 SubdividingMenu::addMenu(QMenu *menu)
00228 {
00229     QString name = menu->title();
00230 
00231     if (!m_entriesSet) {
00232         m_pendingEntries[name] = menu;
00233         return;
00234     }
00235 
00236     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00237 //        SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00238         QMenu::addMenu(menu);
00239         return;
00240     }
00241 
00242 //    SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00243     m_nameToChunkMenuMap[name]->addMenu(menu);
00244 }
00245 
00246 QMenu *
00247 SubdividingMenu::addMenu(const QString &name)
00248 {
00249     if (!m_entriesSet) {
00250         QMenu *menu = new QMenu(name, this);
00251         menu->setTearOffEnabled(isTearOffEnabled());
00252         m_pendingEntries[name] = menu;
00253         return menu;
00254     }
00255 
00256     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00257 //        SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00258         return QMenu::addMenu(name);
00259     }
00260 
00261 //    SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00262     return m_nameToChunkMenuMap[name]->addMenu(name);
00263 }
00264 
00265 void
00266 SubdividingMenu::addMenu(const QString &name, QMenu *menu)
00267 {
00268     if (!m_entriesSet) {
00269         m_pendingEntries[name] = menu;
00270         return;
00271     }
00272 
00273     if (m_nameToChunkMenuMap.find(name) == m_nameToChunkMenuMap.end()) {
00274 //        SVDEBUG << "SubdividingMenu::addMenu(" << name << "): not found in name-to-chunk map, adding to main menu" << endl;
00275         QMenu::addMenu(menu);
00276         return;
00277     }
00278 
00279 //    SVDEBUG << "SubdividingMenu::addMenu(" << name << "): found in name-to-chunk map for menu " << m_nameToChunkMenuMap[name]->title() << endl;
00280     m_nameToChunkMenuMap[name]->addMenu(menu);
00281 }
00282