1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A MIDI and audio sequencer and musical notation editor. 6 Copyright 2000-2021 the Rosegarden development team. 7 8 Other copyrights also apply to some parts of this work. Please 9 see the AUTHORS file and individual file headers for details. 10 11 This program is free software; you can redistribute it and/or 12 modify it under the terms of the GNU General Public License as 13 published by the Free Software Foundation; either version 2 of the 14 License, or (at your option) any later version. See the file 15 COPYING included with this distribution for more information. 16 */ 17 18 #define RG_MODULE_STRING "[EraseCommand]" 19 20 #include "EraseCommand.h" 21 22 #include "misc/Debug.h" 23 #include "base/NotationTypes.h" 24 #include "base/Selection.h" 25 #include "base/BaseProperties.h" 26 #include "document/BasicSelectionCommand.h" 27 #include "gui/editors/notation/NotationProperties.h" 28 29 #include <QString> 30 31 32 namespace Rosegarden 33 { 34 35 36 EraseCommand::EraseCommand(EventSelection &selection) : 37 BasicSelectionCommand(getGlobalName(), selection, true), 38 m_selection(&selection), 39 m_relayoutEndTime(getEndTime()) 40 { 41 // nothing else 42 } 43 44 EraseCommand::~EraseCommand() 45 { 46 // ??? MEMORY LEAK (confirmed) delete here isn't a reliable solution. 47 //delete m_selection; 48 } 49 50 void 51 EraseCommand::modifySegment() 52 { 53 bool needRelayOut = eraseInSegment(m_selection); 54 if (needRelayOut) 55 { m_relayoutEndTime = getSegment().getEndTime(); } 56 } 57 58 // Erase the events in segment that are in selection. 59 // @return 60 // whether any deletions that affect later in the segment were done, 61 // meaning key or clef deletions. 62 bool 63 EraseCommand::eraseInSegment(EventSelection *selection) 64 { 65 RG_DEBUG << "EraseCommand::eraseInSegment"; 66 timeT startTime = selection->getStartTime(); 67 timeT endTime = selection->getEndTime(); 68 Segment &segment = selection->getSegment(); 69 70 bool erasedLongEffectEvent = false; 71 72 std::vector<Event *> toErase; 73 EventSelection::eventcontainer::iterator i; 74 75 for (i = selection->getSegmentEvents().begin(); 76 i != selection->getSegmentEvents().end(); ++i) { 77 78 if ((*i)->isa(Clef::EventType) || 79 (*i)->isa(Key ::EventType)) { 80 erasedLongEffectEvent = true; 81 } else if ((*i)->isa(Indication::EventType)) { 82 83 try { 84 int graceToAdjust = 0; 85 int minGraceSubOrdering = 0; 86 int maxDeltaGraceSubOrdering = 0; 87 int indicationSubOrdering = (*i)->getSubOrdering(); 88 int minSubOrdering = 0; 89 90 // Adjust suborderings of any existing grace notes if necessary. 91 92 Segment::iterator h, j; 93 segment.getTimeSlice((*i)->getAbsoluteTime(), h, j); 94 for (Segment::iterator k = h; k != j; ++k) { 95 if ((*k)->has(BaseProperties::IS_GRACE_NOTE)) { 96 if ((*k)->getSubOrdering() < indicationSubOrdering) { 97 ++graceToAdjust; 98 if ((*k)->getSubOrdering() < minGraceSubOrdering) { 99 minGraceSubOrdering = (*k)->getSubOrdering(); 100 maxDeltaGraceSubOrdering = 101 indicationSubOrdering - minGraceSubOrdering; 102 } 103 } 104 } else if ((*i) != (*k) && 105 (*k)->getSubOrdering() < minSubOrdering) { 106 minSubOrdering = (*k)->getSubOrdering(); 107 } 108 } 109 110 if (graceToAdjust > 0 && 111 minGraceSubOrdering < indicationSubOrdering && 112 minSubOrdering > indicationSubOrdering && 113 maxDeltaGraceSubOrdering >= graceToAdjust) { 114 int incr = minSubOrdering - indicationSubOrdering; 115 std::vector<Event *> toInsert, toErase; 116 for (Segment::iterator k = h; k != j; ++k) { 117 if ((*k)->has(BaseProperties::IS_GRACE_NOTE) && 118 (*k)->getSubOrdering() < indicationSubOrdering) { 119 // Subordering of the grace note is incremented to 120 // avoid (a rare) relevant decrement of that value. 121 toErase.push_back(*k); 122 toInsert.push_back 123 (new Event(**k, 124 (*k)->getAbsoluteTime(), 125 (*k)->getDuration(), 126 (*k)->getSubOrdering() + incr, 127 (*k)->getNotationAbsoluteTime(), 128 (*k)->getNotationDuration())); 129 } 130 } 131 for (std::vector<Event *>::iterator k = toErase.begin(); 132 k != toErase.end(); ++k) segment.eraseSingle(*k); 133 for (std::vector<Event *>::iterator k = toInsert.begin(); 134 k != toInsert.end(); ++k) segment.insert(*k); 135 } 136 137 Indication indication(**i); 138 if (indication.isOttavaType()) { 139 140 for (Segment::iterator j = segment.findTime ((*i)->getAbsoluteTime()); 141 j != segment.findTime 142 ((*i)->getAbsoluteTime() + indication.getIndicationDuration()); 143 ++j) { 144 (*j)->unset(NotationProperties::OTTAVA_SHIFT); 145 } 146 } 147 } catch (...) {} 148 } 149 150 // We used to do this by calling SegmentNotationHelper::deleteEvent 151 // on each event in the selection, but it's probably easier to 152 // cope with general selections by deleting everything in the 153 // selection and then normalizing the rests. The deleteEvent 154 // mechanism is still the more sensitive way to do it for single 155 // events, and it's what's used by EraseEventCommand and thus 156 // the notation eraser tool. 157 158 toErase.push_back(*i); 159 } 160 161 for (size_t j = 0; j < toErase.size(); ++j) { 162 segment.eraseSingle(toErase[j]); 163 } 164 165 segment.normalizeRests(startTime, endTime); 166 return erasedLongEffectEvent; 167 } 168 169 timeT 170 EraseCommand::getRelayoutEndTime() 171 { 172 return m_relayoutEndTime; 173 } 174 175 } 176