annotate base/Selection.cpp @ 389:a1b6d2e33cab

* document library dependencies * remove dependency of transform on audioio
author Chris Cannam
date Thu, 13 Mar 2008 10:12:14 +0000
parents 70a232b1f12a
children 6a94bb528e9d
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@8 2
Chris@8 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@8 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@8 14 */
Chris@8 15
Chris@8 16 #include "Selection.h"
Chris@314 17 #include <QTextStream>
Chris@8 18
Chris@8 19 Selection::Selection() :
Chris@8 20 m_startFrame(0),
Chris@8 21 m_endFrame(0)
Chris@8 22 {
Chris@8 23 }
Chris@8 24
Chris@8 25 Selection::Selection(size_t startFrame, size_t endFrame) :
Chris@8 26 m_startFrame(startFrame),
Chris@8 27 m_endFrame(endFrame)
Chris@8 28 {
Chris@8 29 if (m_startFrame > m_endFrame) {
Chris@8 30 size_t tmp = m_endFrame;
Chris@8 31 m_endFrame = m_startFrame;
Chris@8 32 m_startFrame = tmp;
Chris@8 33 }
Chris@8 34 }
Chris@8 35
Chris@8 36 Selection::Selection(const Selection &s) :
Chris@8 37 m_startFrame(s.m_startFrame),
Chris@8 38 m_endFrame(s.m_endFrame)
Chris@8 39 {
Chris@8 40 }
Chris@8 41
Chris@8 42 Selection &
Chris@8 43 Selection::operator=(const Selection &s)
Chris@8 44 {
Chris@8 45 if (this != &s) {
Chris@8 46 m_startFrame = s.m_startFrame;
Chris@8 47 m_endFrame = s.m_endFrame;
Chris@8 48 }
Chris@8 49 return *this;
Chris@8 50 }
Chris@8 51
Chris@8 52 Selection::~Selection()
Chris@8 53 {
Chris@8 54 }
Chris@8 55
Chris@8 56 bool
Chris@8 57 Selection::isEmpty() const
Chris@8 58 {
Chris@8 59 return m_startFrame == m_endFrame;
Chris@8 60 }
Chris@8 61
Chris@8 62 size_t
Chris@8 63 Selection::getStartFrame() const
Chris@8 64 {
Chris@8 65 return m_startFrame;
Chris@8 66 }
Chris@8 67
Chris@8 68 size_t
Chris@8 69 Selection::getEndFrame() const
Chris@8 70 {
Chris@8 71 return m_endFrame;
Chris@8 72 }
Chris@8 73
Chris@8 74 bool
Chris@9 75 Selection::contains(size_t frame) const
Chris@9 76 {
Chris@9 77 return (frame >= m_startFrame) && (frame < m_endFrame);
Chris@9 78 }
Chris@9 79
Chris@9 80 bool
Chris@8 81 Selection::operator<(const Selection &s) const
Chris@8 82 {
Chris@9 83 if (isEmpty()) {
Chris@9 84 if (s.isEmpty()) return false;
Chris@9 85 else return true;
Chris@9 86 } else {
Chris@9 87 if (s.isEmpty()) return false;
Chris@9 88 else return (m_startFrame < s.m_startFrame);
Chris@9 89 }
Chris@8 90 }
Chris@8 91
Chris@8 92 bool
Chris@8 93 Selection::operator==(const Selection &s) const
Chris@8 94 {
Chris@9 95 if (isEmpty()) return s.isEmpty();
Chris@9 96
Chris@8 97 return (m_startFrame == s.m_startFrame &&
Chris@8 98 m_endFrame == s.m_endFrame);
Chris@8 99 }
Chris@8 100
Chris@24 101
Chris@24 102 MultiSelection::MultiSelection()
Chris@24 103 {
Chris@24 104 }
Chris@24 105
Chris@24 106 MultiSelection::~MultiSelection()
Chris@24 107 {
Chris@24 108 }
Chris@24 109
Chris@24 110 const MultiSelection::SelectionList &
Chris@24 111 MultiSelection::getSelections() const
Chris@24 112 {
Chris@24 113 return m_selections;
Chris@24 114 }
Chris@24 115
Chris@24 116 void
Chris@24 117 MultiSelection::setSelection(const Selection &selection)
Chris@24 118 {
Chris@24 119 clearSelections();
Chris@24 120 addSelection(selection);
Chris@24 121 }
Chris@24 122
Chris@24 123 void
Chris@24 124 MultiSelection::addSelection(const Selection &selection)
Chris@24 125 {
Chris@24 126 m_selections.insert(selection);
Chris@24 127
Chris@24 128 // Cope with a sitation where the new selection overlaps one or
Chris@24 129 // more existing ones. This is a terribly inefficient way to do
Chris@24 130 // this, but that probably isn't significant in real life.
Chris@24 131
Chris@24 132 // It's essential for the correct operation of
Chris@24 133 // getContainingSelection that the selections do not overlap, so
Chris@24 134 // this is not just a frill.
Chris@24 135
Chris@24 136 for (SelectionList::iterator i = m_selections.begin();
Chris@24 137 i != m_selections.end(); ) {
Chris@24 138
Chris@24 139 SelectionList::iterator j = i;
Chris@24 140 if (++j == m_selections.end()) break;
Chris@24 141
Chris@24 142 if (i->getEndFrame() >= j->getStartFrame()) {
Chris@24 143 Selection merged(i->getStartFrame(),
Chris@24 144 std::max(i->getEndFrame(), j->getEndFrame()));
Chris@24 145 m_selections.erase(i);
Chris@24 146 m_selections.erase(j);
Chris@24 147 m_selections.insert(merged);
Chris@24 148 i = m_selections.begin();
Chris@24 149 } else {
Chris@24 150 ++i;
Chris@24 151 }
Chris@24 152 }
Chris@24 153 }
Chris@24 154
Chris@24 155 void
Chris@24 156 MultiSelection::removeSelection(const Selection &selection)
Chris@24 157 {
Chris@24 158 //!!! Likewise this needs to cope correctly with the situation
Chris@24 159 //where selection is not one of the original selection set but
Chris@24 160 //simply overlaps one of them (cutting down the original selection
Chris@24 161 //appropriately)
Chris@24 162
Chris@24 163 if (m_selections.find(selection) != m_selections.end()) {
Chris@24 164 m_selections.erase(selection);
Chris@24 165 }
Chris@24 166 }
Chris@24 167
Chris@24 168 void
Chris@24 169 MultiSelection::clearSelections()
Chris@24 170 {
Chris@24 171 if (!m_selections.empty()) {
Chris@24 172 m_selections.clear();
Chris@24 173 }
Chris@24 174 }
Chris@24 175
Chris@300 176 void
Chris@300 177 MultiSelection::getExtents(size_t &startFrame, size_t &endFrame) const
Chris@300 178 {
Chris@300 179 startFrame = 0;
Chris@300 180 endFrame = 0;
Chris@300 181
Chris@300 182 for (SelectionList::const_iterator i = m_selections.begin();
Chris@300 183 i != m_selections.end(); ++i) {
Chris@300 184
Chris@300 185 if (i == m_selections.begin() || i->getStartFrame() < startFrame) {
Chris@300 186 startFrame = i->getStartFrame();
Chris@300 187 }
Chris@300 188
Chris@300 189 if (i == m_selections.begin() || i->getEndFrame() > endFrame) {
Chris@300 190 endFrame = i->getEndFrame();
Chris@300 191 }
Chris@300 192 }
Chris@300 193 }
Chris@300 194
Chris@24 195 Selection
Chris@36 196 MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const
Chris@24 197 {
Chris@24 198 // This scales very badly with the number of selections, but it's
Chris@24 199 // more efficient for very small numbers of selections than a more
Chris@24 200 // scalable method, and I think that may be what we need
Chris@24 201
Chris@24 202 for (SelectionList::const_iterator i = m_selections.begin();
Chris@24 203 i != m_selections.end(); ++i) {
Chris@24 204
Chris@24 205 if (i->contains(frame)) return *i;
Chris@24 206
Chris@24 207 if (i->getStartFrame() > frame) {
Chris@24 208 if (defaultToFollowing) return *i;
Chris@24 209 else return Selection();
Chris@24 210 }
Chris@24 211 }
Chris@24 212
Chris@24 213 return Selection();
Chris@24 214 }
Chris@46 215
Chris@314 216 void
Chris@314 217 MultiSelection::toXml(QTextStream &stream, QString indent,
Chris@314 218 QString extraAttributes) const
Chris@46 219 {
Chris@314 220 stream << indent << QString("<selections %1>\n").arg(extraAttributes);
Chris@46 221 for (SelectionList::iterator i = m_selections.begin();
Chris@46 222 i != m_selections.end(); ++i) {
Chris@314 223 stream << indent
Chris@314 224 << QString(" <selection start=\"%1\" end=\"%2\"/>\n")
Chris@46 225 .arg(i->getStartFrame()).arg(i->getEndFrame());
Chris@46 226 }
Chris@314 227 stream << indent << "</selections>\n";
Chris@46 228 }
Chris@46 229