ux: drop last-reference confirm from sample remove; silent remove via undo (R-B)
This commit is contained in:
+6
-35
@@ -758,12 +758,10 @@ void doBankTransferSelected(bool copy) {
|
||||
// SCOPE (fork R-A): this-bank only — the sole surfaced verb. The RemoveScope::AllBanks
|
||||
// seam stays latent in the model; nothing here reaches for it.
|
||||
//
|
||||
// CONFIRM-ON-LAST-REFERENCE (guardrail): a remove that would orphan a file (no OTHER
|
||||
// bank references its content hash after the remove) earns a confirm; a remove of a
|
||||
// still-referenced sample does not. BATCH UX: for a multi-select we compute the
|
||||
// last-reference set BEFORE mutating (removal changes the reference graph), then fire a
|
||||
// SINGLE confirm summarizing the N that would orphan — not one dialog per sample. If
|
||||
// none would orphan, no confirm fires at all (the confirm is earned by actual risk).
|
||||
// SILENT REMOVE: removes proceed without a confirm dialog. Recoverability is provided
|
||||
// by the batched REAPER undo (R-B) — one Ctrl-Z restores the index entry. Files are
|
||||
// never deleted by remove (orphaned-until-prune is unchanged). hashReferencedElsewhere
|
||||
// is a tested model API retained for Phase R prune; it has no shell caller here.
|
||||
void doBankRemoveSelected() {
|
||||
const std::vector<std::string> selected = bankPanelSelectedSampleIds();
|
||||
if (selected.empty()) {
|
||||
@@ -772,41 +770,14 @@ void doBankRemoveSelected() {
|
||||
}
|
||||
const std::string srcId = bankPanelSelectedSourceBankId();
|
||||
BankBook& book = g_session->book();
|
||||
const Bank* src = book.bank(srcId);
|
||||
if (src == nullptr) {
|
||||
if (book.bank(srcId) == nullptr) {
|
||||
ShowConsoleMsg("ReaSampler: the selection's bank no longer exists.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Count the samples whose file this remove would orphan — computed on the CURRENT
|
||||
// (pre-mutation) reference graph so a same-hash sibling in another bank counts as a
|
||||
// surviving reference. Resolve by id against the live source index (ids, not cached
|
||||
// refs); an id no longer present is skipped (it removes to a no-op below).
|
||||
int orphanCount = 0;
|
||||
for (const std::string& sampleId : selected) {
|
||||
const Sample* s = src->index.query(sampleId);
|
||||
if (s == nullptr) continue; // already gone; not a last-reference orphan
|
||||
if (!book.hashReferencedElsewhere(s->contentHash, srcId)) ++orphanCount;
|
||||
}
|
||||
|
||||
if (orphanCount > 0) {
|
||||
const std::string msg =
|
||||
std::to_string(orphanCount) +
|
||||
(orphanCount == 1 ? " selected sample is" : " selected samples are") +
|
||||
" in no other bank.\n\nRemoving " +
|
||||
(orphanCount == 1 ? "it" : "them") +
|
||||
" drops the index entry only -- the file stays on disk until you prune "
|
||||
"(it is never deleted by remove).\n\nRemove anyway?";
|
||||
const int r = ShowMessageBox(msg.c_str(),
|
||||
"ReaSampler: remove last-reference sample(s)", 4);
|
||||
if (r != 6) return; // 6 == YES; anything else cancels (SDK ~6544)
|
||||
}
|
||||
|
||||
// Perform the removes (this-bank scope). Pass ids by value — no BankIndex& is cached
|
||||
// across the loop's mutations. Count real drops so the no-op guardrail can skip the
|
||||
// undo point when nothing was removed (every id was already absent). The per-outcome
|
||||
// console summary was dropped (m11 chatter policy); only the "did anything change?"
|
||||
// signal the undo guardrail needs is retained.
|
||||
// undo point when nothing was removed (every id was already absent).
|
||||
int removed = 0;
|
||||
for (const std::string& sampleId : selected) {
|
||||
if (book.removeSample(sampleId, srcId, RemoveScope::ThisBank) ==
|
||||
|
||||
+7
-31
@@ -1365,38 +1365,14 @@ void transferSamples(const std::vector<std::string>& sampleIds,
|
||||
|
||||
// Remove `sampleIds` from `srcBankId` (index-only, this-bank scope). Non-destructive to
|
||||
// the file: a last-reference remove leaves the file on disk, orphaned until Phase R
|
||||
// prune — remove NEVER deletes bytes (the manifest is untouched). Confirm-on-last-
|
||||
// reference guardrail: a single confirm summarizing the N whose files this would orphan
|
||||
// (computed on the PRE-mutation reference graph), fired only when at least one would
|
||||
// orphan. Ids passed by value — no BankIndex& cached across the loop's mutations.
|
||||
// prune — remove NEVER deletes bytes (the manifest is untouched). Removes are silent
|
||||
// (no confirm dialog); recoverability is provided by the batched REAPER undo (R-B) —
|
||||
// one Ctrl-Z restores the index entry. Ids passed by value — no BankIndex& cached
|
||||
// across the loop's mutations.
|
||||
void removeSamples(const std::vector<std::string>& sampleIds,
|
||||
const std::string& srcBankId) {
|
||||
if (!book() || sampleIds.empty()) return;
|
||||
const Bank* src = book()->bank(srcBankId);
|
||||
if (!src) return;
|
||||
|
||||
// Count files this remove would orphan — computed BEFORE mutating, so a same-hash
|
||||
// sibling in another bank counts as a surviving reference.
|
||||
int orphanCount = 0;
|
||||
for (const std::string& sid : sampleIds) {
|
||||
const Sample* s = src->index.query(sid);
|
||||
if (!s) continue; // already gone; not a last-reference orphan
|
||||
if (!book()->hashReferencedElsewhere(s->contentHash, srcBankId)) ++orphanCount;
|
||||
}
|
||||
|
||||
if (orphanCount > 0) {
|
||||
const std::string msg =
|
||||
std::to_string(orphanCount) +
|
||||
(orphanCount == 1 ? " selected sample is" : " selected samples are") +
|
||||
" in no other bank.\n\nRemoving " +
|
||||
(orphanCount == 1 ? "it" : "them") +
|
||||
" drops the index entry only -- the file stays on disk until you prune "
|
||||
"(it is never deleted by remove).\n\nRemove anyway?";
|
||||
// 4 == MB_YESNO. 6=Yes (SDK); anything else cancels.
|
||||
const int r = ShowMessageBox(msg.c_str(),
|
||||
"ReaSampler: remove last-reference sample(s)", 4);
|
||||
if (r != 6) return;
|
||||
}
|
||||
if (!book()->bank(srcBankId)) return;
|
||||
|
||||
int removed = 0;
|
||||
for (const std::string& sid : sampleIds)
|
||||
@@ -1771,8 +1747,8 @@ bool handleKey(int vk) {
|
||||
stopAudition();
|
||||
return true;
|
||||
case VK_DELETE: {
|
||||
// Remove the focused-region selection (B5). Same confirm-on-last-reference
|
||||
// path the context-menu "Remove" uses; a no-op when nothing is selected.
|
||||
// Remove the focused-region selection (B5). Silent; a no-op when nothing
|
||||
// is selected.
|
||||
const std::vector<std::string> sel = focusedSelectionIds();
|
||||
if (sel.empty()) return false; // nothing selected — let the key fall through
|
||||
removeSamples(sel, bankIdForRegion(g_panel.focusedRegion));
|
||||
|
||||
Reference in New Issue
Block a user