Skip to content

Commit 00462fe

Browse files
committed
Update paste and delete behavior
1 parent 1ed4a07 commit 00462fe

File tree

2 files changed

+135
-67
lines changed

2 files changed

+135
-67
lines changed

src/plugins/coreplugin/project/document/DspxDocument.cpp

Lines changed: 128 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}, [] {

src/plugins/coreplugin/project/document/DspxDocument_p.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ namespace Core {
3131
std::optional<DspxClipboardData> buildLabelClipboardData(int playheadPosition) const;
3232
std::optional<DspxClipboardData> buildTrackClipboardData() const;
3333

34-
bool pasteClipboardData(const DspxClipboardData &data, int playheadPosition);
35-
bool pasteTempos(const QList<QDspx::Tempo> &tempos, const DspxClipboardData &data, int playheadPosition);
36-
bool pasteLabels(const QList<QDspx::Label> &labels, const DspxClipboardData &data, int playheadPosition);
37-
bool pasteTracks(const QList<QDspx::Track> &tracks);
34+
bool pasteClipboardData(const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems);
35+
bool pasteTempos(const QList<QDspx::Tempo> &tempos, const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems);
36+
bool pasteLabels(const QList<QDspx::Label> &labels, const DspxClipboardData &data, int playheadPosition, QList<QObject *> &pastedItems);
37+
bool pasteTracks(const QList<QDspx::Track> &tracks, QList<QObject *> &pastedItems);
3838

3939
bool deleteSelection();
40+
int deleteTempos();
41+
int deleteLabels();
42+
int deleteTracks();
4043

4144
template<typename Signal>
4245
bool emitOnChange(bool value, bool &cache, Signal signal);

0 commit comments

Comments
 (0)