Logo Search packages:      
Sourcecode: canorus version File versions  Download package

void CAMainWin::copySelection ( CAScoreViewPort v  ) 

Backend for Edit->Copy.

Definition at line 4539 of file mainwin.cpp.

References CALyricsContext::addSyllable(), CAStaff::addVoice(), CAVoice::append(), CALyricsContext::associatedVoice(), CAMusElement::clone(), CASlur::clone(), CATuplet::clone(), CAPlayable::clone(), CAMusElement::context(), CASheet::contextCount(), CASheet::contextList(), CAContext::contextType(), CAMusElement::isPlayable(), CAMusElement::musElementType(), CATuplet::noteList(), CAStaff::numberOfLines(), CANote::phrasingSlurEnd(), CANote::phrasingSlurStart(), CAScoreViewPort::selection(), CANote::setPhrasingSlurStart(), CANote::setSlurStart(), CANote::setTieStart(), CAScoreViewPort::sheet(), CANote::slurEnd(), CANote::slurStart(), CASlur::slurType(), CANote::tieEnd(), CANote::tieStart(), CAMusElement::timeStart(), CAPlayable::tuplet(), CAPlayable::voice(), CAStaff::voiceCount(), and CAStaff::voiceIndex().

Referenced by on_uiCopy_triggered(), and on_uiCut_triggered().

                                                  {
      if ( v->selection().size() ) {
            CASheet* currentSheet = v->sheet();
            QHash<CAContext*, QList<CAMusElement*> > eltMap;
            QList<CAContext*> contexts;
            for(int i=0; i < currentSheet->contextCount(); i++)
                  contexts << 0;

            foreach(CADrawableMusElement* drawable, v->selection()) {
                  CAMusElement* elt;
                  CAContext* context;
                  if(!(elt=drawable->musElement()) || !(context = elt->context()))
                        continue;
                  if(elt->musElementType() == CAMusElement::Mark || elt->musElementType() == CAMusElement::Tuplet || elt->musElementType() == CAMusElement::Slur)
                        continue;   // marks are cloned together with their associated element, no need to clone them separately.
                                          // tuplets and slurs cannot be inserted into a context or a voice
                  if(context->contextType() != CAContext::Staff && context->contextType() != CAContext::LyricsContext)
                        continue; // only these context types are impl'd. If we added anything else, we'd have old pointers in the context list.
                  eltMap[context] << elt;
                  int idx = currentSheet->contextList().indexOf(context);
                  contexts[idx] = context;
            }
            contexts.removeAll(0);
            // contexts now contains the contexts of the selected elements, in the correct order.

            // Copy staff elements
            QHash<CAVoice*, CAVoice*> voiceMap; // all voices in selection
            for(int i=0; i<contexts.size(); i++)
            {
                  CAContext* context = contexts[i];
                  if(context->contextType() != CAContext::Staff)
                        continue;
                  CAStaff* staff = static_cast<CAStaff*>(context);
                  CAStaff* newStaff = new CAStaff("", 0, staff->numberOfLines());
                  contexts[i] = newStaff;

                  QList<CAVoice*> voices;
                  for(int i=0; i<staff->voiceCount(); i++)
                        voices << 0;

                  // create voices
                  foreach(CAMusElement* elt, eltMap[context])
                  {
                        if(!elt->isPlayable())
                              continue;
                        CAVoice* voice = static_cast<CAPlayable*>(elt)->voice();
                        int idx = staff->voiceIndex(voice);
                        if(!voices[idx])
                              voiceMap[voice] = voices[idx] = new CAVoice("", newStaff);

                  }

                  CAVoice* defaultVoice = 0; // for non-playable elements
                  foreach(CAVoice* voice, voices)
                  {
                        if(voice) {
                              defaultVoice = voice;
                              break;
                        }
                  }
                  if(!defaultVoice)
                        defaultVoice = new CAVoice("", newStaff);
                  // future FIXME (also in pasteAt): tuplets across staves (when cross-staff beam are impl'd GUI-wise).
                  QHash<CATuplet*, QList<CAPlayable*> > tupletMap;
                  QHash<CASlur*, CANote*> slurMap; //FIXME cross-staff slurs, when the crash is fixed (try cutting one)
                  foreach(CAMusElement* elt, eltMap[context])
                  {
                        if(elt->isPlayable()) {
                              CAPlayable* pl = static_cast<CAPlayable*>(elt);
                              CAVoice* voice = pl->voice();
                              int idx = staff->voiceIndex(voice);
                              bool addToChord = false;
                              int eltidx = eltMap[context].indexOf(elt);
                              CANote* note = (pl->musElementType() == CAMusElement::Note)?static_cast<CANote*>(pl):0;
                              if(note) {
                                    CAMusElement* prev = 0;
                                    for(int previdx = eltidx-1; previdx >= 0; previdx--) {
                                          if((prev = eltMap[context][previdx]) && prev->musElementType() == CAMusElement::Note
                                                      && pl->voice() == static_cast<CAPlayable*>(prev)->voice()) {
                                                CANote *prevNote = static_cast<CANote*>(prev);
                                                addToChord = prev->timeStart() == note->timeStart();
                                                break;
                                          }
                                    }
                              }
                              CAPlayable* cloned = pl->clone(voices[idx]);
                              voices[idx]->append(cloned, addToChord);
                              if(pl->tuplet())
                              {
                                    tupletMap[pl->tuplet()] << cloned;
                                    if(tupletMap[pl->tuplet()].size() == pl->tuplet()->noteList().size())
                                          pl->tuplet()->clone(tupletMap[pl->tuplet()]);
                              }
                              if(note)
                              {
                                    QList<CASlur*> slurs;
                                    slurs << note->tieStart() << note->tieEnd() << note->slurStart() << note->slurEnd() << note->phrasingSlurStart() << note->phrasingSlurEnd();
                                    slurs.removeAll(0);
                                    foreach(CASlur* s, slurs)
                                    {
                                          if(!slurMap.contains(s))
                                                slurMap[s] = static_cast<CANote*>(cloned);
                                          else {
                                                CANote* noteStart = slurMap[s], *noteEnd = static_cast<CANote*>(cloned);
                                                CASlur* newSlur = s->clone(noteStart->context(), noteStart, noteEnd);
                                                switch (s->slurType()) {
                                                      case CASlur::TieType:
                                                            noteStart->setTieStart( newSlur );
                                                            noteEnd->setTieEnd( newSlur );
                                                            break;
                                                      case CASlur::SlurType:
                                                            noteStart->setSlurStart( newSlur );
                                                            noteEnd->setSlurEnd( newSlur );
                                                            break;
                                                      case CASlur::PhrasingSlurType:
                                                            noteStart->setPhrasingSlurStart( newSlur );
                                                            noteEnd->setPhrasingSlurEnd( newSlur );
                                                            break;
                                                }
                                          }
                                    }
                              }
                        } else
                              defaultVoice->append(elt->clone(newStaff));
                  }

                  voices.removeAll(0);
                  if(voices.isEmpty())
                        voices << defaultVoice;

                  CAStaff *last = static_cast<CAStaff*>(currentSheet->contextList().last());
                  foreach(CAVoice* voice, voices)
                        newStaff->addVoice(voice);
            }

            // Copy lyrics
            for(int i=0; i<contexts.size(); i++)
            {
                  CAContext *context = contexts[i];
                  if(context->contextType() != CAContext::LyricsContext)
                        continue;
                  CALyricsContext* lc = static_cast<CALyricsContext*>(context);
                  CAVoice* associated = voiceMap[lc->associatedVoice()]; // init'd to 0 if map doesn't contain the voice.
                  CALyricsContext* newLc = new CALyricsContext("", 0 /*FIXME*/, associated);
                  contexts[i] = newLc;
                  foreach(CAMusElement* elt, eltMap[context])
                        newLc->addSyllable(static_cast<CASyllable*>(elt->clone(newLc)), false);
            }

            QApplication::clipboard()->setMimeData( new CAMimeData(contexts) );
      }
}


Generated by  Doxygen 1.6.0   Back to index