Skip to content

Commit

Permalink
Merge pull request #25441 from cbjeukendrup/instrumentspanel/replace_…
Browse files Browse the repository at this point in the history
…instrument_crash

Fix crash when replacing instrument via popup in instruments panel
  • Loading branch information
cbjeukendrup authored Nov 20, 2024
2 parents fd97bf1 + 6102fc3 commit 1dce053
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ StyledPopupView {

property bool needActiveFirstItem: false

signal replaceInstrumentRequested()
signal resetAllFormattingRequested()

contentHeight: contentColumn.childrenRect.height

onOpened: {
Expand Down Expand Up @@ -113,9 +116,8 @@ StyledPopupView {
visible: settingsModel.isMainScore

onClicked: {
root.replaceInstrumentRequested()
root.close()

settingsModel.replaceInstrument()
}
}

Expand All @@ -130,9 +132,8 @@ StyledPopupView {
visible: !settingsModel.isMainScore

onClicked: {
root.resetAllFormattingRequested()
root.close()

settingsModel.resetAllFormatting()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ FocusableControl {
Loader {
id: popupLoader

property alias openedPopup: popupLoader.item
property bool isPopupOpened: Boolean(openedPopup) && openedPopup.isOpened
readonly property StyledPopupView openedPopup: popupLoader.item as StyledPopupView
readonly property bool isPopupOpened: Boolean(openedPopup) && openedPopup.isOpened

function openPopup(comp, btn, item) {
function openPopup(comp: Component, btn: Item, item) {
popupLoader.sourceComponent = comp
if (!openedPopup) {
return
Expand All @@ -152,10 +152,7 @@ FocusableControl {

openedPopup.closed.connect(function() {
root.popupClosed()

Qt.callLater(function() {
popupLoader.sourceComponent = null
})
sourceComponent = null
})

openedPopup.open()
Expand All @@ -173,6 +170,22 @@ FocusableControl {

InstrumentSettingsPopup {
anchorItem: popupAnchorItem

onReplaceInstrumentRequested: {
// The popup would close when the dialog to select the new
// instrument is shown; when it closes, it is unloaded, i.e.
// deleted, which means that it is deleted while a signal
// handler inside it is being executed. This causes a crash.
// To prevent that, let the popup close itself, and perform the
// actual operation "later", i.e. not (directly or indirectly)
// inside the signal handler in the popup.
Qt.callLater(model.itemRole.replaceInstrument)
}

onResetAllFormattingRequested: {
// Same as above
Qt.callLater(model.itemRole.resetAllFormatting)
}
}
}

Expand Down
53 changes: 0 additions & 53 deletions src/instrumentsscene/view/instrumentsettingsmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
*/
#include "instrumentsettingsmodel.h"

#include "log.h"
#include "translation.h"

using namespace muse;
using namespace mu::instrumentsscene;
using namespace mu::notation;
Expand Down Expand Up @@ -59,50 +56,6 @@ void InstrumentSettingsModel::load(const QVariant& instrument)
emit dataChanged();
}

void InstrumentSettingsModel::replaceInstrument()
{
if (!masterNotationParts()) {
return;
}

RetVal<Instrument> selectedInstrument = selectInstrumentsScenario()->selectInstrument(m_instrumentKey);
if (!selectedInstrument.ret) {
LOGE() << selectedInstrument.ret.toString();
return;
}

const Instrument& newInstrument = selectedInstrument.val;
masterNotationParts()->replaceInstrument(m_instrumentKey, newInstrument);

m_instrumentKey.instrumentId = newInstrument.id();
m_instrumentName = newInstrument.nameAsPlainText();
m_instrumentAbbreviature = newInstrument.abbreviatureAsPlainText();

emit dataChanged();
}

void InstrumentSettingsModel::resetAllFormatting()
{
if (!masterNotationParts() || !notationParts()) {
return;
}

std::string title = muse::trc("instruments", "Are you sure you want to reset all formatting?");
std::string body = muse::trc("instruments", "This action can not be undone");

IInteractive::Button button = interactive()->question(title, body, {
IInteractive::Button::No,
IInteractive::Button::Yes
}).standardButton();

if (button == IInteractive::Button::No) {
return;
}

const Part* masterPart = masterNotationParts()->part(m_instrumentKey.partId);
notationParts()->replacePart(m_instrumentKey.partId, masterPart->clone());
}

QString InstrumentSettingsModel::instrumentName() const
{
return m_instrumentName;
Expand Down Expand Up @@ -154,9 +107,3 @@ INotationPartsPtr InstrumentSettingsModel::notationParts() const
INotationPtr notation = currentNotation();
return notation ? notation->parts() : nullptr;
}

INotationPartsPtr InstrumentSettingsModel::masterNotationParts() const
{
INotationPtr notation = currentMasterNotation();
return notation ? notation->parts() : nullptr;
}
7 changes: 0 additions & 7 deletions src/instrumentsscene/view/instrumentsettingsmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@

#include "modularity/ioc.h"
#include "context/iglobalcontext.h"
#include "notation/iselectinstrumentscenario.h"
#include "global/iinteractive.h"

#include "notation/notationtypes.h"

Expand All @@ -38,9 +36,7 @@ class InstrumentSettingsModel : public QObject, public muse::async::Asyncable
{
Q_OBJECT

INJECT(notation::ISelectInstrumentsScenario, selectInstrumentsScenario)
INJECT(context::IGlobalContext, context)
INJECT(muse::IInteractive, interactive)

Q_PROPERTY(QString instrumentName READ instrumentName WRITE setInstrumentName NOTIFY dataChanged)
Q_PROPERTY(QString abbreviature READ abbreviature WRITE setAbbreviature NOTIFY dataChanged)
Expand All @@ -51,8 +47,6 @@ class InstrumentSettingsModel : public QObject, public muse::async::Asyncable
explicit InstrumentSettingsModel(QObject* parent = nullptr);

Q_INVOKABLE void load(const QVariant& instrument);
Q_INVOKABLE void replaceInstrument();
Q_INVOKABLE void resetAllFormatting();

QString instrumentName() const;
QString abbreviature() const;
Expand All @@ -71,7 +65,6 @@ public slots:
notation::INotationPtr currentNotation() const;
notation::INotationPtr currentMasterNotation() const;
notation::INotationPartsPtr notationParts() const;
notation::INotationPartsPtr masterNotationParts() const;

notation::InstrumentKey m_instrumentKey;
QString m_instrumentName;
Expand Down
2 changes: 1 addition & 1 deletion src/instrumentsscene/view/instrumentspaneltreemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ void InstrumentsPanelTreeModel::load()
beginResetModel();
deleteItems();

m_rootItem = new RootTreeItem(m_masterNotation, m_notation);
m_rootItem = new RootTreeItem(m_masterNotation, m_notation, this);

async::NotifyList<const Part*> masterParts = m_masterNotation->parts()->partList();
sortParts(masterParts);
Expand Down
47 changes: 41 additions & 6 deletions src/instrumentsscene/view/parttreeitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ using namespace muse;
using ItemType = InstrumentsTreeItemType::ItemType;

PartTreeItem::PartTreeItem(IMasterNotationPtr masterNotation, INotationPtr notation, QObject* parent)
: AbstractInstrumentsPanelTreeItem(ItemType::PART, masterNotation, notation, parent)
: AbstractInstrumentsPanelTreeItem(ItemType::PART, masterNotation, notation, parent), Injectable(iocCtxForQmlObject(this))
{
listenVisibilityChanged();
}
Expand Down Expand Up @@ -133,11 +133,6 @@ size_t PartTreeItem::resolveNewPartIndex(const ID& partId) const
return parts.size();
}

QString PartTreeItem::instrumentId() const
{
return m_instrumentId;
}

MoveParams PartTreeItem::buildMoveParams(int sourceRow, int count, AbstractInstrumentsPanelTreeItem* destinationParent,
int destinationRow) const
{
Expand Down Expand Up @@ -192,3 +187,43 @@ void PartTreeItem::removeChildren(int row, int count, bool deleteChild)

AbstractInstrumentsPanelTreeItem::removeChildren(row, count, deleteChild);
}

QString PartTreeItem::instrumentId() const
{
return m_instrumentId;
}

void PartTreeItem::replaceInstrument()
{
InstrumentKey instrumentKey;
instrumentKey.partId = id();
instrumentKey.instrumentId = m_instrumentId;
instrumentKey.tick = Part::MAIN_INSTRUMENT_TICK;

RetVal<Instrument> selectedInstrument = selectInstrumentsScenario()->selectInstrument(instrumentKey);
if (!selectedInstrument.ret) {
LOGE() << selectedInstrument.ret.toString();
return;
}

const Instrument& newInstrument = selectedInstrument.val;
masterNotation()->parts()->replaceInstrument(instrumentKey, newInstrument);
}

void PartTreeItem::resetAllFormatting()
{
std::string title = muse::trc("instruments", "Are you sure you want to reset all formatting?");
std::string body = muse::trc("instruments", "This action can not be undone");

IInteractive::Button button = interactive()->question(title, body, {
IInteractive::Button::No,
IInteractive::Button::Yes
}).standardButton();

if (button != IInteractive::Button::Yes) {
return;
}

const Part* masterPart = masterNotation()->parts()->part(id());
notation()->parts()->replacePart(id(), masterPart->clone());
}
15 changes: 11 additions & 4 deletions src/instrumentsscene/view/parttreeitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,25 @@

#include "abstractinstrumentspaneltreeitem.h"

#include "notation/inotationparts.h"
#include "modularity/ioc.h"
#include "iinteractive.h"
#include "notation/iselectinstrumentscenario.h"

namespace mu::instrumentsscene {
class PartTreeItem : public AbstractInstrumentsPanelTreeItem
class PartTreeItem : public AbstractInstrumentsPanelTreeItem, public muse::Injectable
{
Q_OBJECT

muse::Inject<notation::ISelectInstrumentsScenario> selectInstrumentsScenario { this };
muse::Inject<muse::IInteractive> interactive { this };

public:
PartTreeItem(notation::IMasterNotationPtr masterNotation, notation::INotationPtr notation, QObject* parent);

void init(const notation::Part* masterPart);

bool isSelectable() const override;

Q_INVOKABLE QString instrumentId() const;

MoveParams buildMoveParams(int sourceRow, int count, AbstractInstrumentsPanelTreeItem* destinationParent,
int destinationRow) const override;

Expand All @@ -48,6 +51,10 @@ class PartTreeItem : public AbstractInstrumentsPanelTreeItem

void removeChildren(int row, int count, bool deleteChild) override;

Q_INVOKABLE QString instrumentId() const;
Q_INVOKABLE void replaceInstrument();
Q_INVOKABLE void resetAllFormatting();

private:
void listenVisibilityChanged();
void createAndAddPart(const muse::ID& masterPartId);
Expand Down

0 comments on commit 1dce053

Please sign in to comment.