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 Chris Cannam. 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 "Selection.h" lbajardsilogic@0: lbajardsilogic@0: Selection::Selection() : lbajardsilogic@0: m_startFrame(0), lbajardsilogic@0: m_endFrame(0) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Selection::Selection(size_t startFrame, size_t endFrame) : lbajardsilogic@0: m_startFrame(startFrame), lbajardsilogic@0: m_endFrame(endFrame) lbajardsilogic@0: { lbajardsilogic@0: if (m_startFrame > m_endFrame) { lbajardsilogic@0: size_t tmp = m_endFrame; lbajardsilogic@0: m_endFrame = m_startFrame; lbajardsilogic@0: m_startFrame = tmp; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Selection::Selection(const Selection &s) : lbajardsilogic@0: m_startFrame(s.m_startFrame), lbajardsilogic@0: m_endFrame(s.m_endFrame) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Selection & lbajardsilogic@0: Selection::operator=(const Selection &s) lbajardsilogic@0: { lbajardsilogic@0: if (this != &s) { lbajardsilogic@0: m_startFrame = s.m_startFrame; lbajardsilogic@0: m_endFrame = s.m_endFrame; lbajardsilogic@0: } lbajardsilogic@0: return *this; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Selection::~Selection() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: Selection::isEmpty() const lbajardsilogic@0: { lbajardsilogic@0: return m_startFrame == m_endFrame; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t lbajardsilogic@0: Selection::getStartFrame() const lbajardsilogic@0: { lbajardsilogic@0: return m_startFrame; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t lbajardsilogic@0: Selection::getEndFrame() const lbajardsilogic@0: { lbajardsilogic@0: return m_endFrame; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: Selection::contains(size_t frame) const lbajardsilogic@0: { lbajardsilogic@0: return (frame >= m_startFrame) && (frame < m_endFrame); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: Selection::operator<(const Selection &s) const lbajardsilogic@0: { lbajardsilogic@0: if (isEmpty()) { lbajardsilogic@0: if (s.isEmpty()) return false; lbajardsilogic@0: else return true; lbajardsilogic@0: } else { lbajardsilogic@0: if (s.isEmpty()) return false; lbajardsilogic@0: else return (m_startFrame < s.m_startFrame); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: Selection::operator==(const Selection &s) const lbajardsilogic@0: { lbajardsilogic@0: if (isEmpty()) return s.isEmpty(); lbajardsilogic@0: lbajardsilogic@0: return (m_startFrame == s.m_startFrame && lbajardsilogic@0: m_endFrame == s.m_endFrame); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: MultiSelection::MultiSelection() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: MultiSelection::~MultiSelection() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: const MultiSelection::SelectionList & lbajardsilogic@0: MultiSelection::getSelections() const lbajardsilogic@0: { lbajardsilogic@0: return m_selections; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: MultiSelection::setSelection(const Selection &selection) lbajardsilogic@0: { lbajardsilogic@0: clearSelections(); lbajardsilogic@0: addSelection(selection); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: MultiSelection::addSelection(const Selection &selection) lbajardsilogic@0: { lbajardsilogic@0: m_selections.insert(selection); lbajardsilogic@0: lbajardsilogic@0: // Cope with a sitation where the new selection overlaps one or lbajardsilogic@0: // more existing ones. This is a terribly inefficient way to do lbajardsilogic@0: // this, but that probably isn't significant in real life. lbajardsilogic@0: lbajardsilogic@0: // It's essential for the correct operation of lbajardsilogic@0: // getContainingSelection that the selections do not overlap, so lbajardsilogic@0: // this is not just a frill. lbajardsilogic@0: lbajardsilogic@0: for (SelectionList::iterator i = m_selections.begin(); lbajardsilogic@0: i != m_selections.end(); ) { lbajardsilogic@0: lbajardsilogic@0: SelectionList::iterator j = i; lbajardsilogic@0: if (++j == m_selections.end()) break; lbajardsilogic@0: lbajardsilogic@0: if (i->getEndFrame() >= j->getStartFrame()) { lbajardsilogic@0: Selection merged(i->getStartFrame(), lbajardsilogic@0: std::max(i->getEndFrame(), j->getEndFrame())); lbajardsilogic@0: m_selections.erase(i); lbajardsilogic@0: m_selections.erase(j); lbajardsilogic@0: m_selections.insert(merged); lbajardsilogic@0: i = m_selections.begin(); lbajardsilogic@0: } else { lbajardsilogic@0: ++i; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: MultiSelection::removeSelection(const Selection &selection) lbajardsilogic@0: { lbajardsilogic@0: //!!! Likewise this needs to cope correctly with the situation lbajardsilogic@0: //where selection is not one of the original selection set but lbajardsilogic@0: //simply overlaps one of them (cutting down the original selection lbajardsilogic@0: //appropriately) lbajardsilogic@0: lbajardsilogic@0: if (m_selections.find(selection) != m_selections.end()) { lbajardsilogic@0: m_selections.erase(selection); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: MultiSelection::clearSelections() lbajardsilogic@0: { lbajardsilogic@0: if (!m_selections.empty()) { lbajardsilogic@0: m_selections.clear(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Selection lbajardsilogic@0: MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const lbajardsilogic@0: { lbajardsilogic@0: // This scales very badly with the number of selections, but it's lbajardsilogic@0: // more efficient for very small numbers of selections than a more lbajardsilogic@0: // scalable method, and I think that may be what we need lbajardsilogic@0: lbajardsilogic@0: for (SelectionList::const_iterator i = m_selections.begin(); lbajardsilogic@0: i != m_selections.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: if (i->contains(frame)) return *i; lbajardsilogic@0: lbajardsilogic@0: if (i->getStartFrame() > frame) { lbajardsilogic@0: if (defaultToFollowing) return *i; lbajardsilogic@0: else return Selection(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return Selection(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: MultiSelection::toXmlString(QString indent, lbajardsilogic@0: QString extraAttributes) const lbajardsilogic@0: { lbajardsilogic@0: QString s; lbajardsilogic@0: s += indent + QString("\n").arg(extraAttributes); lbajardsilogic@0: for (SelectionList::const_iterator i = m_selections.begin(); lbajardsilogic@0: i != m_selections.end(); ++i) { lbajardsilogic@0: s += indent + QString(" \n") lbajardsilogic@0: .arg(i->getStartFrame()).arg(i->getEndFrame()); lbajardsilogic@0: } lbajardsilogic@0: s += indent + "\n"; lbajardsilogic@0: return s; lbajardsilogic@0: } lbajardsilogic@0: