@@ -282,14 +282,14 @@ namespace Core {
282282 return data;
283283 }
284284
285- bool DspxDocumentPrivate::pasteClipboardData (const DspxClipboardData &data, int playheadPosition) {
285+ bool DspxDocumentPrivate::pasteClipboardData (const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems ) {
286286 switch (data.type ()) {
287287 case DspxClipboardData::Tempo:
288- return pasteTempos (data.tempos (), data, playheadPosition);
288+ return pasteTempos (data.tempos (), data, playheadPosition, pastedItems );
289289 case DspxClipboardData::Label:
290- return pasteLabels (data.labels (), data, playheadPosition);
290+ return pasteLabels (data.labels (), data, playheadPosition, pastedItems );
291291 case DspxClipboardData::Track:
292- return pasteTracks (data.tracks ());
292+ return pasteTracks (data.tracks (), pastedItems );
293293 case DspxClipboardData::Clip:
294294 case DspxClipboardData::Note:
295295 // TODO paste support for clips and notes
@@ -298,7 +298,7 @@ namespace Core {
298298 return false ;
299299 }
300300
301- bool DspxDocumentPrivate::pasteTempos (const QList<QDspx::Tempo> &tempos, const DspxClipboardData &data, int playheadPosition) {
301+ bool DspxDocumentPrivate::pasteTempos (const QList<QDspx::Tempo> &tempos, const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems ) {
302302 if (!model || !model->timeline () || tempos.isEmpty ())
303303 return false ;
304304
@@ -351,6 +351,7 @@ namespace Core {
351351 }
352352
353353 inserted = true ;
354+ pastedItems.append (tempo);
354355 const auto overlappingItems = tempoSequence->slice (tempoData.pos , 1 );
355356 for (auto *overlappingItem : overlappingItems) {
356357 if (overlappingItem == tempo)
@@ -369,7 +370,7 @@ namespace Core {
369370 return inserted;
370371 }
371372
372- bool DspxDocumentPrivate::pasteLabels (const QList<QDspx::Label> &labels, const DspxClipboardData &data, int playheadPosition) {
373+ bool DspxDocumentPrivate::pasteLabels (const QList<QDspx::Label> &labels, const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems ) {
373374 if (!model || !model->timeline () || labels.isEmpty ())
374375 return false ;
375376
@@ -420,6 +421,7 @@ namespace Core {
420421 continue ;
421422 }
422423 inserted = true ;
424+ pastedItems.append (label);
423425 }
424426
425427 if (inserted)
@@ -430,7 +432,7 @@ namespace Core {
430432 return inserted;
431433 }
432434
433- bool DspxDocumentPrivate::pasteTracks (const QList<QDspx::Track> &tracks) {
435+ bool DspxDocumentPrivate::pasteTracks (const QList<QDspx::Track> &tracks, QList<QObject *> &pastedItems ) {
434436 if (!model || tracks.isEmpty ())
435437 return false ;
436438
@@ -457,6 +459,7 @@ namespace Core {
457459 }
458460 insertionIndex++;
459461 inserted = true ;
462+ pastedItems.append (track);
460463 }
461464
462465 if (inserted)
@@ -471,61 +474,17 @@ namespace Core {
471474 if (!selectionModel || selectionModel->selectedCount () <= 0 )
472475 return false ;
473476
474- bool removed = false ;
475477 int removedCount = 0 ;
476478 switch (selectionModel->selectionType ()) {
477- case dspx::SelectionModel::ST_Tempo: {
478- auto *tempoSequence = model->timeline ()->tempos ();
479- for (auto *item : selectionModel->tempoSelectionModel ()->selectedItems ()) {
480- if (item->pos () == 0 ) {
481- const auto overlappingItems = tempoSequence->slice (0 , 1 );
482- if (overlappingItems.size () == 1 ) {
483- continue ;
484- }
485- }
486- if (tempoSequence->removeItem (item)) {
487- model->destroyItem (item);
488- removed = true ;
489- ++removedCount;
490- }
491- }
479+ case dspx::SelectionModel::ST_Tempo:
480+ removedCount = deleteTempos ();
492481 break ;
493- }
494- case dspx::SelectionModel::ST_Label: {
495- auto *labelSequence = model->timeline ()->labels ();
496- for (auto *item : selectionModel->labelSelectionModel ()->selectedItems ()) {
497- if (labelSequence->removeItem (item)) {
498- model->destroyItem (item);
499- removed = true ;
500- ++removedCount;
501- }
502- }
482+ case dspx::SelectionModel::ST_Label:
483+ removedCount = deleteLabels ();
503484 break ;
504- }
505- case dspx::SelectionModel::ST_Track: {
506- auto *trackList = model->tracks ();
507- const auto allTracks = trackList->items ();
508- QList<int > indexes;
509- for (auto *item : selectionModel->trackSelectionModel ()->selectedItems ()) {
510- const int index = allTracks.indexOf (item);
511- if (index >= 0 )
512- indexes.append (index);
513- }
514-
515- std::sort (indexes.begin (), indexes.end (), [](int lhs, int rhs) {
516- return lhs > rhs;
517- });
518-
519- for (const int index : std::as_const (indexes)) {
520- auto *removedTrack = trackList->removeItem (index);
521- if (removedTrack) {
522- model->destroyItem (removedTrack);
523- removed = true ;
524- ++removedCount;
525- }
526- }
485+ case dspx::SelectionModel::ST_Track:
486+ removedCount = deleteTracks ();
527487 break ;
528- }
529488 case dspx::SelectionModel::ST_Clip:
530489 case dspx::SelectionModel::ST_Note:
531490 case dspx::SelectionModel::ST_AnchorNode:
@@ -536,12 +495,83 @@ namespace Core {
536495 break ;
537496 }
538497
539- if (removed )
498+ if (removedCount > 0 )
540499 qCInfo (lcDspxDocument) << " Deleted selection" << selectionTypeName (selectionModel->selectionType ()) << " count" << removedCount;
541500 else
542501 qCDebug (lcDspxDocument) << " Delete selection produced no changes" << selectionTypeName (selectionModel->selectionType ());
543502
544- return removed;
503+ return removedCount > 0 ;
504+ }
505+
506+ int DspxDocumentPrivate::deleteTempos () {
507+ if (!model || !selectionModel || !model->timeline ())
508+ return 0 ;
509+
510+ auto *tempoSequence = model->timeline ()->tempos ();
511+ int removedCount = 0 ;
512+ for (auto *item : selectionModel->tempoSelectionModel ()->selectedItems ()) {
513+ if (!item)
514+ continue ;
515+
516+ // Protect the initial tempo at position 0 when it is the only one.
517+ if (item->pos () == 0 ) {
518+ const auto overlappingItems = tempoSequence->slice (0 , 1 );
519+ if (overlappingItems.size () == 1 )
520+ continue ;
521+ }
522+
523+ if (tempoSequence->removeItem (item)) {
524+ model->destroyItem (item);
525+ ++removedCount;
526+ }
527+ }
528+ return removedCount;
529+ }
530+
531+ int DspxDocumentPrivate::deleteLabels () {
532+ if (!model || !selectionModel || !model->timeline ())
533+ return 0 ;
534+
535+ auto *labelSequence = model->timeline ()->labels ();
536+ int removedCount = 0 ;
537+ for (auto *item : selectionModel->labelSelectionModel ()->selectedItems ()) {
538+ if (!item)
539+ continue ;
540+ if (labelSequence->removeItem (item)) {
541+ model->destroyItem (item);
542+ ++removedCount;
543+ }
544+ }
545+ return removedCount;
546+ }
547+
548+ int DspxDocumentPrivate::deleteTracks () {
549+ if (!model || !selectionModel)
550+ return 0 ;
551+
552+ auto *trackList = model->tracks ();
553+ const auto allTracks = trackList->items ();
554+ QList<int > indexes;
555+ for (auto *item : selectionModel->trackSelectionModel ()->selectedItems ()) {
556+ const int index = allTracks.indexOf (item);
557+ if (index >= 0 )
558+ indexes.append (index);
559+ }
560+
561+ std::sort (indexes.begin (), indexes.end (), [](int lhs, int rhs) {
562+ return lhs > rhs;
563+ });
564+
565+ int removedCount = 0 ;
566+ for (const int index : std::as_const (indexes)) {
567+ auto *removedTrack = trackList->removeItem (index);
568+ if (removedTrack) {
569+ model->destroyItem (removedTrack);
570+ ++removedCount;
571+ }
572+ }
573+
574+ return removedCount;
545575 }
546576
547577 DspxDocument::DspxDocument (QObject *parent) : QObject(parent), d_ptr(new DspxDocumentPrivate) {
@@ -665,24 +695,59 @@ namespace Core {
665695 return tr (" Pasting selection" );
666696 }();
667697
698+ QList<QObject *> pastedItems;
668699 bool pasted = false ;
669- transactionController ()->beginScopedTransaction (transactionName, [=, &pasted, &data] {
670- pasted = d->pasteClipboardData (data, playheadPosition);
700+ transactionController ()->beginScopedTransaction (transactionName, [=, &pasted, &data, &pastedItems ] {
701+ pasted = d->pasteClipboardData (data, playheadPosition, pastedItems );
671702 return pasted;
672703 }, [] {
673704 qCCritical (lcDspxDocument ()) << " Failed to paste in scoped transaction" ;
674705 });
675706
707+ if (pasted && d->selectionModel ) {
708+ bool first = true ;
709+ for (auto *item : std::as_const (pastedItems)) {
710+ if (!item)
711+ continue ;
712+ const auto command = first
713+ ? dspx::SelectionModel::Select | dspx::SelectionModel::SetCurrentItem | dspx::SelectionModel::ClearPreviousSelection
714+ : dspx::SelectionModel::Select;
715+ d->selectionModel ->select (item, command, dspx::SelectionModel::selectionTypeFromItem (item));
716+ first = false ;
717+ }
718+ }
719+
676720 qCInfo (lcDspxDocument) << " Paste result" << clipboardTypeName (data.type ()) << (pasted ? " succeeded" : " no changes" );
677721 }
678722
679723 void DspxDocument::deleteSelection () {
680724 Q_D (DspxDocument);
681725 if (!anyItemsSelected ())
682726 return ;
683- qCInfo (lcDspxDocument) << " Delete selection" ;
727+ const auto selectionType = d->selectionModel ? d->selectionModel ->selectionType () : dspx::SelectionModel::ST_None;
728+ const QString transactionName = [selectionType, this ] {
729+ switch (selectionType) {
730+ case dspx::SelectionModel::ST_Tempo:
731+ return tr (" Deleting tempo" );
732+ case dspx::SelectionModel::ST_Label:
733+ return tr (" Deleting label" );
734+ case dspx::SelectionModel::ST_Track:
735+ return tr (" Deleting track" );
736+ case dspx::SelectionModel::ST_Clip:
737+ return tr (" Deleting clip" );
738+ case dspx::SelectionModel::ST_Note:
739+ return tr (" Deleting note" );
740+ case dspx::SelectionModel::ST_AnchorNode:
741+ return tr (" Deleting anchor node" );
742+ case dspx::SelectionModel::ST_None:
743+ default :
744+ return tr (" Deleting selection" );
745+ }
746+ }();
747+
748+ qCInfo (lcDspxDocument) << " Delete selection" << selectionTypeName (selectionType);
684749 bool deleted = false ;
685- transactionController ()->beginScopedTransaction (tr ( " Deleting selection " ) , [=, &deleted] {
750+ transactionController ()->beginScopedTransaction (transactionName , [=, &deleted] {
686751 deleted = d->deleteSelection ();
687752 return deleted;
688753 }, [] {
0 commit comments