annotate base/Selection.cpp @ 1247:8f076d02569a piper

Make SVDEBUG always write to a log file -- formerly this was disabled in NDEBUG builds. I think there's little use to that, it just means that we keep adding more cerr debug output because we aren't getting the log we need. And SVDEBUG logging is not usually used in tight loops, I don't think the performance overhead is too serious. Also update the About box.
author Chris Cannam
date Thu, 03 Nov 2016 14:57:00 +0000
parents cc27f35aa75c
children 48e9f538e6e9
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@1038 25 Selection::Selection(sv_frame_t startFrame, sv_frame_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@1038 30 sv_frame_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@1038 62 sv_frame_t
Chris@8 63 Selection::getStartFrame() const
Chris@8 64 {
Chris@8 65 return m_startFrame;
Chris@8 66 }
Chris@8 67
Chris@1038 68 sv_frame_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@1038 75 Selection::contains(sv_frame_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@1038 177 MultiSelection::getExtents(sv_frame_t &startFrame, sv_frame_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@1038 196 MultiSelection::getContainingSelection(sv_frame_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