annotate base/Selection.cpp @ 308:14e0f60435b8

* Make it possible to drop audio files, layer files, session files and images onto SV panes. Need to do a bit more work on where we expect the dropped file to go, particularly in the case of audio files -- at the moment they're always opened in new panes, but it may be better to by default replace whatever is in the target pane.
author Chris Cannam
date Wed, 10 Oct 2007 15:18:02 +0000
parents 5877d68815c7
children 70a232b1f12a
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@8 17
Chris@8 18 Selection::Selection() :
Chris@8 19 m_startFrame(0),
Chris@8 20 m_endFrame(0)
Chris@8 21 {
Chris@8 22 }
Chris@8 23
Chris@8 24 Selection::Selection(size_t startFrame, size_t endFrame) :
Chris@8 25 m_startFrame(startFrame),
Chris@8 26 m_endFrame(endFrame)
Chris@8 27 {
Chris@8 28 if (m_startFrame > m_endFrame) {
Chris@8 29 size_t tmp = m_endFrame;
Chris@8 30 m_endFrame = m_startFrame;
Chris@8 31 m_startFrame = tmp;
Chris@8 32 }
Chris@8 33 }
Chris@8 34
Chris@8 35 Selection::Selection(const Selection &s) :
Chris@8 36 m_startFrame(s.m_startFrame),
Chris@8 37 m_endFrame(s.m_endFrame)
Chris@8 38 {
Chris@8 39 }
Chris@8 40
Chris@8 41 Selection &
Chris@8 42 Selection::operator=(const Selection &s)
Chris@8 43 {
Chris@8 44 if (this != &s) {
Chris@8 45 m_startFrame = s.m_startFrame;
Chris@8 46 m_endFrame = s.m_endFrame;
Chris@8 47 }
Chris@8 48 return *this;
Chris@8 49 }
Chris@8 50
Chris@8 51 Selection::~Selection()
Chris@8 52 {
Chris@8 53 }
Chris@8 54
Chris@8 55 bool
Chris@8 56 Selection::isEmpty() const
Chris@8 57 {
Chris@8 58 return m_startFrame == m_endFrame;
Chris@8 59 }
Chris@8 60
Chris@8 61 size_t
Chris@8 62 Selection::getStartFrame() const
Chris@8 63 {
Chris@8 64 return m_startFrame;
Chris@8 65 }
Chris@8 66
Chris@8 67 size_t
Chris@8 68 Selection::getEndFrame() const
Chris@8 69 {
Chris@8 70 return m_endFrame;
Chris@8 71 }
Chris@8 72
Chris@8 73 bool
Chris@9 74 Selection::contains(size_t frame) const
Chris@9 75 {
Chris@9 76 return (frame >= m_startFrame) && (frame < m_endFrame);
Chris@9 77 }
Chris@9 78
Chris@9 79 bool
Chris@8 80 Selection::operator<(const Selection &s) const
Chris@8 81 {
Chris@9 82 if (isEmpty()) {
Chris@9 83 if (s.isEmpty()) return false;
Chris@9 84 else return true;
Chris@9 85 } else {
Chris@9 86 if (s.isEmpty()) return false;
Chris@9 87 else return (m_startFrame < s.m_startFrame);
Chris@9 88 }
Chris@8 89 }
Chris@8 90
Chris@8 91 bool
Chris@8 92 Selection::operator==(const Selection &s) const
Chris@8 93 {
Chris@9 94 if (isEmpty()) return s.isEmpty();
Chris@9 95
Chris@8 96 return (m_startFrame == s.m_startFrame &&
Chris@8 97 m_endFrame == s.m_endFrame);
Chris@8 98 }
Chris@8 99
Chris@24 100
Chris@24 101 MultiSelection::MultiSelection()
Chris@24 102 {
Chris@24 103 }
Chris@24 104
Chris@24 105 MultiSelection::~MultiSelection()
Chris@24 106 {
Chris@24 107 }
Chris@24 108
Chris@24 109 const MultiSelection::SelectionList &
Chris@24 110 MultiSelection::getSelections() const
Chris@24 111 {
Chris@24 112 return m_selections;
Chris@24 113 }
Chris@24 114
Chris@24 115 void
Chris@24 116 MultiSelection::setSelection(const Selection &selection)
Chris@24 117 {
Chris@24 118 clearSelections();
Chris@24 119 addSelection(selection);
Chris@24 120 }
Chris@24 121
Chris@24 122 void
Chris@24 123 MultiSelection::addSelection(const Selection &selection)
Chris@24 124 {
Chris@24 125 m_selections.insert(selection);
Chris@24 126
Chris@24 127 // Cope with a sitation where the new selection overlaps one or
Chris@24 128 // more existing ones. This is a terribly inefficient way to do
Chris@24 129 // this, but that probably isn't significant in real life.
Chris@24 130
Chris@24 131 // It's essential for the correct operation of
Chris@24 132 // getContainingSelection that the selections do not overlap, so
Chris@24 133 // this is not just a frill.
Chris@24 134
Chris@24 135 for (SelectionList::iterator i = m_selections.begin();
Chris@24 136 i != m_selections.end(); ) {
Chris@24 137
Chris@24 138 SelectionList::iterator j = i;
Chris@24 139 if (++j == m_selections.end()) break;
Chris@24 140
Chris@24 141 if (i->getEndFrame() >= j->getStartFrame()) {
Chris@24 142 Selection merged(i->getStartFrame(),
Chris@24 143 std::max(i->getEndFrame(), j->getEndFrame()));
Chris@24 144 m_selections.erase(i);
Chris@24 145 m_selections.erase(j);
Chris@24 146 m_selections.insert(merged);
Chris@24 147 i = m_selections.begin();
Chris@24 148 } else {
Chris@24 149 ++i;
Chris@24 150 }
Chris@24 151 }
Chris@24 152 }
Chris@24 153
Chris@24 154 void
Chris@24 155 MultiSelection::removeSelection(const Selection &selection)
Chris@24 156 {
Chris@24 157 //!!! Likewise this needs to cope correctly with the situation
Chris@24 158 //where selection is not one of the original selection set but
Chris@24 159 //simply overlaps one of them (cutting down the original selection
Chris@24 160 //appropriately)
Chris@24 161
Chris@24 162 if (m_selections.find(selection) != m_selections.end()) {
Chris@24 163 m_selections.erase(selection);
Chris@24 164 }
Chris@24 165 }
Chris@24 166
Chris@24 167 void
Chris@24 168 MultiSelection::clearSelections()
Chris@24 169 {
Chris@24 170 if (!m_selections.empty()) {
Chris@24 171 m_selections.clear();
Chris@24 172 }
Chris@24 173 }
Chris@24 174
Chris@300 175 void
Chris@300 176 MultiSelection::getExtents(size_t &startFrame, size_t &endFrame) const
Chris@300 177 {
Chris@300 178 startFrame = 0;
Chris@300 179 endFrame = 0;
Chris@300 180
Chris@300 181 for (SelectionList::const_iterator i = m_selections.begin();
Chris@300 182 i != m_selections.end(); ++i) {
Chris@300 183
Chris@300 184 if (i == m_selections.begin() || i->getStartFrame() < startFrame) {
Chris@300 185 startFrame = i->getStartFrame();
Chris@300 186 }
Chris@300 187
Chris@300 188 if (i == m_selections.begin() || i->getEndFrame() > endFrame) {
Chris@300 189 endFrame = i->getEndFrame();
Chris@300 190 }
Chris@300 191 }
Chris@300 192 }
Chris@300 193
Chris@24 194 Selection
Chris@36 195 MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const
Chris@24 196 {
Chris@24 197 // This scales very badly with the number of selections, but it's
Chris@24 198 // more efficient for very small numbers of selections than a more
Chris@24 199 // scalable method, and I think that may be what we need
Chris@24 200
Chris@24 201 for (SelectionList::const_iterator i = m_selections.begin();
Chris@24 202 i != m_selections.end(); ++i) {
Chris@24 203
Chris@24 204 if (i->contains(frame)) return *i;
Chris@24 205
Chris@24 206 if (i->getStartFrame() > frame) {
Chris@24 207 if (defaultToFollowing) return *i;
Chris@24 208 else return Selection();
Chris@24 209 }
Chris@24 210 }
Chris@24 211
Chris@24 212 return Selection();
Chris@24 213 }
Chris@46 214
Chris@46 215 QString
Chris@46 216 MultiSelection::toXmlString(QString indent,
Chris@46 217 QString extraAttributes) const
Chris@46 218 {
Chris@46 219 QString s;
Chris@46 220 s += 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@46 223 s += indent + QString(" <selection start=\"%1\" end=\"%2\"/>\n")
Chris@46 224 .arg(i->getStartFrame()).arg(i->getEndFrame());
Chris@46 225 }
Chris@46 226 s += indent + "</selections>\n";
Chris@46 227 return s;
Chris@46 228 }
Chris@46 229