implemented creating and removing of excerpts

This commit is contained in:
Roman Pudashkin 2020-10-08 12:02:49 +02:00 committed by Igor Korsukov
parent 28fe6ceab4
commit cb1fe3a1ad
26 changed files with 429 additions and 164 deletions

View file

@ -32,7 +32,7 @@ FocusableItem {
anchors.fill: parent
color: root.accentButton ? ui.theme.accentColor : ui.theme.buttonColor
color: normalStateColor
opacity: ui.theme.buttonOpacityNormal
border.width: 0
radius: 3

View file

@ -6,13 +6,16 @@ RadioDelegate {
default property Component contentComponent
property alias backgroundColor: backgroundRect.color
property alias radius: backgroundRect.radius
property color normalStateColor: ui.theme.buttonColor
property color hoverStateColor: ui.theme.buttonColor
property color pressedStateColor: ui.theme.buttonColor
property color selectedStateColor: ui.theme.accentColor
implicitHeight: 30
implicitWidth: ListView.view ? (ListView.view.width - (ListView.view.spacing * (ListView.view.count - 1))) / ListView.view.count
: 30
hoverEnabled: true
background: Rectangle {
@ -20,10 +23,9 @@ RadioDelegate {
anchors.fill: parent
color: ui.theme.buttonColor
opacity: root.checked || root.pressed ? 0 : ui.theme.buttonOpacityNormal
color: normalStateColor
opacity: ui.theme.buttonOpacityNormal
border.width: 0
radius: 2
}
@ -39,56 +41,39 @@ RadioDelegate {
}
}
indicator: Item {
}
indicator: Item {}
states: [
State {
name: "PRESSED"
when: root.pressed
PropertyChanges {
target: backgroundRect
color: ui.theme.accentColor
opacity: ui.theme.accentOpacityHit
border.width: 0
}
},
State {
name: "SELECTED"
when: root.checked && !root.hovered
PropertyChanges {
target: backgroundRect
color: ui.theme.accentColor
opacity: ui.theme.accentOpacityNormal
border.width: 0
}
},
State {
name: "HOVERED"
when: root.hovered && !root.checked && !root.pressed
PropertyChanges {
target: backgroundRect
color: ui.theme.buttonColor
color: hoverStateColor
opacity: ui.theme.buttonOpacityHover
border.color: ui.theme.strokeColor
border.width: 1
}
},
State {
name: "SELECTED_HOVERED"
when: root.hovered && root.checked
name: "PRESSED"
when: root.pressed && !root.checked
PropertyChanges {
target: backgroundRect
color: ui.theme.accentColor
opacity: ui.theme.accentOpacityHover
border.width: 0
color: pressedStateColor
opacity: ui.theme.buttonOpacityHit
}
},
State {
name: "SELECTED"
when: root.checked
PropertyChanges {
target: backgroundRect
color: selectedStateColor
opacity: ui.theme.buttonOpacityNormal
}
}
]

View file

@ -174,6 +174,7 @@ void Excerpt::createExcerpt(Excerpt* excerpt)
// Set instruments and create linked staves
for (const Part* part : parts) {
Part* p = new Part(score);
p->setId(part->id());
p->setInstrument(*part->instrument());
p->setPartName(part->partName());

View file

@ -1424,7 +1424,7 @@ void Score::hideEmptyStaves(System* system, bool isFirstSystem)
}
}
// dont allow a complete empty system
if (systemIsEmpty) {
if (systemIsEmpty && !_staves.isEmpty()) {
Staff* staff = firstVisible ? firstVisible : _staves.front();
SysStaff* ss = system->staff(staff->idx());
ss->setShow(true);

View file

@ -30,22 +30,28 @@ mu::async::Notification MU4InspectorAdapter::isTextEditingChanged() const
void MU4InspectorAdapter::beginCommand()
{
undoStack()->prepareChanges();
if (undoStack()) {
undoStack()->prepareChanges();
}
}
void MU4InspectorAdapter::endCommand()
{
undoStack()->commitChanges();
if (undoStack()) {
undoStack()->commitChanges();
}
}
void MU4InspectorAdapter::updateStyleValue(const Ms::Sid& styleId, const QVariant& newValue)
{
style()->setStyleValue(styleId, newValue);
if (style()) {
style()->setStyleValue(styleId, newValue);
}
}
QVariant MU4InspectorAdapter::styleValue(const Ms::Sid& styleId)
{
return style()->styleValue(styleId);
return style() ? style()->styleValue(styleId) : QVariant();
}
void MU4InspectorAdapter::showSpecialCharactersDialog()
@ -124,7 +130,7 @@ void MU4InspectorAdapter::updateNotation()
INotationUndoStack* MU4InspectorAdapter::undoStack() const
{
IF_ASSERT_FAILED(context() && context()->currentNotation()) {
if (!context() || !context()->currentNotation()) {
return nullptr;
}
@ -133,7 +139,7 @@ INotationUndoStack* MU4InspectorAdapter::undoStack() const
INotationStyle* MU4InspectorAdapter::style() const
{
IF_ASSERT_FAILED(context() && context()->currentNotation()) {
if (!context() || !context()->currentNotation()) {
return nullptr;
}

View file

@ -209,6 +209,7 @@ void InspectorListModel::subscribeOnSelectionChanges()
if (!m_notation) {
setElementList(QList<Ms::Element*>());
return;
}
m_notation->interaction()->selectionChanged().onNotify(this, [this]() {

View file

@ -162,7 +162,7 @@ InspectorSectionView {
checked: root.model && !root.model.horizontalAlignment.isUndefined ? root.model.horizontalAlignment.value === modelData["typeRole"]
: false
backgroundColor: ui.theme.backgroundPrimaryColor
normalStateColor: ui.theme.backgroundPrimaryColor
onToggled: {
root.model.horizontalAlignment.value = modelData["typeRole"]
@ -199,7 +199,7 @@ InspectorSectionView {
checked: root.model && !root.model.verticalAlignment.isUndefined ? root.model.verticalAlignment.value === modelData["typeRole"]
: false
backgroundColor: ui.theme.backgroundPrimaryColor
normalStateColor: ui.theme.backgroundPrimaryColor
onToggled: {
root.model.verticalAlignment.value = modelData["typeRole"]

View file

@ -57,7 +57,7 @@ StyledPopup {
width: 30
backgroundColor: "#00000000"
normalStateColor: "#00000000"
ButtonGroup.group: subscriptOptionsButtonList.radioButtonGroup

View file

@ -22,13 +22,11 @@
#include "inotation.h"
namespace mu {
namespace notation {
namespace mu::notation {
class IExcerptNotation : virtual public INotation
{
};
using IExcerptNotationPtr = std::shared_ptr<IExcerptNotation>;
}
}
#endif // MU_NOTATION_IEXCERPTNOTATION_H

View file

@ -24,8 +24,7 @@
#include "ret.h"
#include "io/path.h"
namespace mu {
namespace notation {
namespace mu::notation {
class IMasterNotation : virtual public INotation
{
public:
@ -35,10 +34,12 @@ public:
virtual Ret createNew(const ScoreCreateOptions& scoreInfo) = 0;
virtual std::vector<IExcerptNotationPtr> excerpts() const = 0;
virtual async::Notification excerptsChanged() const = 0;
virtual IExcerptNotationPtr appendExcerpt(const Meta& meta) = 0;
virtual void removeExcerpt(IExcerptNotationPtr excerpt) = 0;
};
using IMasterNotationPtr = std::shared_ptr<IMasterNotation>;
}
}
#endif // MU_NOTATION_IMASTERNOTATION_H

View file

@ -48,6 +48,9 @@ public:
virtual void paint(QPainter* painter) = 0;
virtual QRectF previewRect() const = 0;
virtual ValCh<bool> opened() const = 0;
virtual void setOpened(bool opened) = 0;
// input (mouse)
virtual INotationInteraction* interaction() const = 0;

View file

@ -19,9 +19,27 @@
#include "excerptnotation.h"
#include "libmscore/excerpt.h"
using namespace mu::notation;
ExcerptNotation::ExcerptNotation(Ms::Score* score)
: Notation(score)
ExcerptNotation::ExcerptNotation(Ms::Excerpt* excerpt)
: Notation(excerpt->partScore()), m_excerpt(excerpt)
{
}
ExcerptNotation::~ExcerptNotation()
{
Ms::MasterScore* master = m_excerpt->oscore();
if (master) {
master->removeExcerpt(m_excerpt);
}
delete m_excerpt;
m_excerpt = nullptr;
}
Ms::Excerpt* ExcerptNotation::excerpt() const
{
return m_excerpt;
}

View file

@ -27,14 +27,18 @@ namespace Ms {
class Score;
}
namespace mu {
namespace notation {
namespace mu::notation {
class ExcerptNotation : public IExcerptNotation, public Notation
{
public:
explicit ExcerptNotation(Ms::Score* score);
explicit ExcerptNotation(Ms::Excerpt* excerpt);
~ExcerptNotation() override;
Ms::Excerpt* excerpt() const;
private:
Ms::Excerpt* m_excerpt = nullptr;
};
}
}
#endif // MU_NOTATION_EXCERPTNOTATION_H

View file

@ -32,6 +32,7 @@
#include "libmscore/keysig.h"
#include "libmscore/rest.h"
#include "libmscore/tempotext.h"
#include "libmscore/undo.h"
#include "../notationerrors.h"
@ -80,8 +81,10 @@ mu::Ret MasterNotation::load(const io::path& path, const INotationReaderPtr& rea
MasterScore* score = new MasterScore(scoreGlobal()->baseStyle());
Ret ret = doLoadScore(score, path, reader);
if (ret) {
setScore(score);
initExcerpts();
}
return ret;
@ -482,19 +485,93 @@ mu::Ret MasterNotation::createNew(const ScoreCreateOptions& scoreOptions)
return make_ret(Err::NoError);
}
void MasterNotation::initExcerpts()
{
MasterScore* master = masterScore();
if (!master) {
return;
}
if (master->excerpts().isEmpty()) {
auto excerpts = Excerpt::createAllExcerpt(master);
for (Excerpt* excerpt : excerpts) {
Score* score = new Score(excerpt->oscore());
excerpt->setPartScore(score);
score->style().set(Sid::createMultiMeasureRests, true);
auto excerptCmdFake = new AddExcerpt(excerpt);
excerptCmdFake->redo(nullptr);
Excerpt::createExcerpt(excerpt);
}
}
for (Excerpt* excerpt: master->excerpts()) {
m_excerpts.push_back(std::make_shared<ExcerptNotation>(excerpt));
}
m_excerptsChanged.notify();
}
std::vector<IExcerptNotationPtr> MasterNotation::excerpts() const
{
std::vector<IExcerptNotationPtr> result;
const MasterScore* master = masterScore();
if (!master) {
return result;
}
for (const Excerpt* excerpt: master->excerpts()) {
IExcerptNotationPtr part = std::make_shared<ExcerptNotation>(excerpt->partScore());
result.push_back(part);
for (auto excerpt: m_excerpts) {
result.push_back(static_cast<IExcerptNotationPtr>(excerpt));
}
return result;
}
Notification MasterNotation::excerptsChanged() const
{
return m_excerptsChanged;
}
IExcerptNotationPtr MasterNotation::appendExcerpt(const Meta& meta)
{
MasterScore* master = masterScore();
if (!master) {
return nullptr;
}
Excerpt* excerpt = new Excerpt(master);
excerpt->setPartScore(new Score(excerpt->oscore()));
excerpt->setTitle(meta.title);
Excerpt::createExcerpt(excerpt);
master->addExcerpt(excerpt);
std::shared_ptr<ExcerptNotation> excerptNotation = std::make_shared<ExcerptNotation>(excerpt);
m_excerpts.push_back(excerptNotation);
m_excerptsChanged.notify();
return excerptNotation;
}
void MasterNotation::removeExcerpt(IExcerptNotationPtr excerpt)
{
MasterScore* master = masterScore();
if (!master) {
return;
}
excerpt->setOpened(false);
for (size_t i = 0; i < m_excerpts.size(); ++i) {
if (static_cast<IExcerptNotationPtr>(m_excerpts[i]) == excerpt) {
master->deleteExcerpt(m_excerpts[i]->excerpt());
m_excerpts.erase(m_excerpts.begin() + i);
break;
}
}
IDList partsIdList;
for (const Part* part: excerpt->parts()->partList()) {
partsIdList << part->id();
}
parts()->removeParts(partsIdList);
m_excerptsChanged.notify();
}

View file

@ -29,8 +29,8 @@ namespace Ms {
class MasterScore;
}
namespace mu {
namespace notation {
namespace mu::notation {
class ExcerptNotation;
class MasterNotation : public IMasterNotation, public Notation
{
INJECT(notation, INotationReadersRegister, readers)
@ -46,6 +46,9 @@ public:
Ret createNew(const ScoreCreateOptions& scoreOptions) override;
std::vector<IExcerptNotationPtr> excerpts() const override;
async::Notification excerptsChanged() const override;
IExcerptNotationPtr appendExcerpt(const Meta& meta) override;
void removeExcerpt(IExcerptNotationPtr excerpt) override;
private:
Ms::MasterScore* masterScore() const;
@ -54,14 +57,19 @@ private:
Ret doLoadScore(Ms::MasterScore* score, const io::path& path, const INotationReaderPtr& reader) const;
mu::RetVal<Ms::MasterScore*> newScore(const ScoreCreateOptions& scoreInfo);
void initExcerpts();
void initParts(Ms::MasterScore* score, const QList<instruments::InstrumentTemplate>& instrumentTemplates);
void initStaff(Ms::Staff* staff, const instruments::InstrumentTemplate& instrumentTemplate,const instruments::StaffType* staffType,
int cidx);
Ms::Instrument instrumentFromTemplate(const instruments::InstrumentTemplate& instrumentTemplate) const;
void numberInstrumentNames(Ms::MasterScore* score);
private:
std::vector<std::shared_ptr<ExcerptNotation> > m_excerpts;
async::Notification m_excerptsChanged;
};
}
}
#endif // MU_NOTATION_MASTERNOTATION_H

View file

@ -41,6 +41,7 @@ using namespace Ms;
Notation::Notation(Score* score)
{
m_scoreGlobal = new MScore(); //! TODO May be static?
m_opened.val = false;
m_interaction = new NotationInteraction(this);
m_midiInput = new NotationMidiInput(this);
@ -166,6 +167,20 @@ void Notation::paint(QPainter* painter)
m_interaction->paint(painter);
}
mu::ValCh<bool> Notation::opened() const
{
return m_opened;
}
void Notation::setOpened(bool opened)
{
if (m_opened.val == opened) {
return;
}
m_opened.set(opened);
}
void Notation::notifyAboutNotationChanged()
{
m_notationChanged.notify();

View file

@ -48,6 +48,9 @@ public:
void paint(QPainter* painter) override;
QRectF previewRect() const override;
ValCh<bool> opened() const override;
void setOpened(bool opened) override;
INotationInteraction* interaction() const override;
INotationMidiInput* midiInput() const override;
@ -81,6 +84,7 @@ private:
QSizeF m_viewSize;
Ms::MScore* m_scoreGlobal = nullptr;
Ms::Score* m_score = nullptr;
ValCh<bool> m_opened;
NotationInteraction* m_interaction = nullptr;
INotationUndoStack* m_undoStackController = nullptr;
INotationStyle* m_style = nullptr;

View file

@ -1272,14 +1272,16 @@ void NotationParts::sortParts(const IDList& instrumentIds)
return part->instrument()->instrumentId();
};
for (size_t i = 0; i < instrumentIds.size(); i++) {
Part* currentPart = score()->parts().at(i);
for (int i = 0; i < instrumentIds.size(); ++i) {
const Part* currentPart = score()->parts().at(i);
if (mainInstrumentId(currentPart) == instrumentIds.at(i)) {
continue;
}
for (int j = i; j < score()->parts().size(); j++) {
Part* part = score()->parts().at(j);
for (int j = i; j < score()->parts().size(); ++j) {
const Part* part = score()->parts().at(j);
if (mainInstrumentId(part) == instrumentIds.at(i)) {
doMovePart(part->id(), currentPart->id());
break;

View file

@ -1,5 +1,6 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import MuseScore.UiComponents 1.0
import MuseScore.Ui 1.0
@ -10,41 +11,41 @@ FlatRadioButton {
signal closeRequested()
width: 100
normalStateColor: ui.theme.backgroundSecondaryColor
hoverStateColor: selectedStateColor
pressedStateColor: selectedStateColor
selectedStateColor: ui.theme.backgroundPrimaryColor
width: 110
radius: 0
RowLayout {
anchors.fill: parent
anchors.leftMargin: 4
anchors.leftMargin: 12
StyledTextLabel {
Layout.alignment: Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
text: root.title
font.pixelSize: 12
}
Item {
FlatButton {
Layout.fillHeight: true
Layout.topMargin: 1
Layout.bottomMargin: 1
Layout.preferredWidth: width
Layout.alignment: Qt.AlignRight
Layout.fillHeight: true
Layout.minimumWidth: 16
StyledIconLabel {
anchors.centerIn: parent
iconCode: IconCode.CLOSE_X_ROUNDED
}
MouseArea {
anchors.fill: parent
onClicked: root.closeRequested()
}
normalStateColor: "transparent"
icon: IconCode.CLOSE_X_ROUNDED
onClicked: root.closeRequested()
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 1
color: ui.theme.strokeColor
}
SeparatorLine { orientation: Qt.Vertical }
}
}

View file

@ -1,17 +1,25 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import MuseScore.NotationScene 1.0
import MuseScore.UiComponents 1.0
Rectangle {
id: root
property alias notationsCount: notationsView.count
height: 32
visible: notationsView.count > 0
color: ui.theme.backgroundSecondaryColor
height: 30
border.width: 1
border.color: ui.theme.strokeColor
NotationSwitchListModel {
id: notationSwitchModel
onCurrentNotationIndexChanged: {
notationsView.currentIndex = index
}
}
Component.onCompleted: {
@ -21,16 +29,18 @@ Rectangle {
RadioButtonGroup {
id: notationsView
width: contentWidth
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: 1
width: Math.min(contentWidth, parent.width)
model: notationSwitchModel
currentIndex: 0
spacing: 0
function setCurrentNotation(index) {
currentIndex = index
notationSwitchModel.setCurrentNotation(index)
}
interactive: width < contentWidth
boundsBehavior: Flickable.StopAtBounds
delegate: NotationSwitchButton {
id: button
@ -50,7 +60,7 @@ Rectangle {
}
onToggled: {
notationsView.setCurrentNotation(model.index)
notationSwitchModel.setCurrentNotation(model.index)
}
onCloseRequested: {
@ -61,7 +71,7 @@ Rectangle {
var index = button.resolveNextNotationIndex()
notationSwitchModel.closeNotation(model.index)
notationsView.setCurrentNotation(index)
notationSwitchModel.setCurrentNotation(index)
}
}
}

View file

@ -8,9 +8,10 @@ FocusScope {
ColumnLayout {
anchors.fill: parent
spacing: 0
NotationSwitchPanel {
Layout.fillWidth: true
visible: notationsCount > 1
}
NotationPaintView {

View file

@ -1,11 +1,15 @@
import QtQuick 2.9
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQml.Models 2.11
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.NotationScene 1.0
QmlDialog {
id: root
width: 600
height: 370
@ -20,21 +24,24 @@ QmlDialog {
id: partsModel
}
ItemSelectionModel {
id: selectionModel
model: partsModel
}
Component.onCompleted: {
partsModel.load()
}
Column {
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 30
Item {
anchors.left: parent.left
anchors.right: parent.right
height: childrenRect.height
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
StyledTextLabel {
anchors.left: parent.left
@ -51,7 +58,9 @@ QmlDialog {
anchors.rightMargin: 8
onClicked: {
partsModel.apply()
partsModel.createNewPart()
root.hide()
}
}
@ -63,7 +72,8 @@ QmlDialog {
icon: IconCode.DELETE_TANK
onClicked: {
partsModel.removeParts(selectionModel.selectedIndexes)
selectionModel.clear()
}
}
}
@ -71,8 +81,8 @@ QmlDialog {
ListView {
id: view
height: 200
width: parent.width
Layout.preferredHeight: 200
Layout.fillWidth: true
spacing: 0
@ -129,15 +139,34 @@ QmlDialog {
SeparatorLine { anchors.bottom: parent.bottom }
property bool selected: false
Connections {
target: selectionModel
function onHasSelectionChanged() {
if (!selectionModel.hasSelection) {
selected = false
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
var index = partsModel.index(model.row, 0)
selectionModel.select(index, ItemSelectionModel.Select)
selected = !selected
}
}
states: [
State {
name: "SELECTED"
when: mouseArea.pressed
when: selected
PropertyChanges {
target: partRect
@ -149,13 +178,28 @@ QmlDialog {
}
}
FlatButton {
anchors.right: parent.right
Row {
Layout.preferredHeight: childrenRect.height
Layout.alignment: Qt.AlignRight
text: qsTrc("notation", "Open all parts")
spacing: 16
onClicked: {
partsModel.openAllParts()
FlatButton {
text: qsTrc("notation", "Cancel")
onClicked: {
root.reject()
}
}
FlatButton {
text: qsTrc("notation", "Open")
onClicked: {
partsModel.apply()
partsModel.openParts(selectionModel.selectedIndexes)
root.hide()
}
}
}
}

View file

@ -31,29 +31,75 @@ NotationSwitchListModel::NotationSwitchListModel(QObject* parent)
void NotationSwitchListModel::load()
{
updateNotations();
loadNotations();
globalContext()->currentMasterNotationChanged().onNotify(this, [this]() {
updateNotations();
context()->currentMasterNotationChanged().onNotify(this, [this]() {
loadNotations();
if (!masterNotation()) {
return;
}
masterNotation()->excerptsChanged().onNotify(this, [this]() {
loadNotations();
});
});
context()->currentNotationChanged().onNotify(this, [this]() {
INotationPtr notation = context()->currentNotation();
if (!notation) {
return;
}
int currentNotationIndex = m_notations.indexOf(notation);
emit currentNotationIndexChanged(currentNotationIndex);
});
}
void NotationSwitchListModel::updateNotations()
void NotationSwitchListModel::loadNotations()
{
IMasterNotationPtr masterNotation = globalContext()->currentMasterNotation();
beginResetModel();
m_notations.clear();
if (masterNotation) {
std::vector<IExcerptNotationPtr> excerpts = masterNotation->excerpts();
m_notations.push_back(masterNotation);
m_notations.insert(m_notations.end(), excerpts.begin(), excerpts.end());
if (!masterNotation()) {
endResetModel();
return;
}
m_notations << masterNotation();
for (IExcerptNotationPtr excerpt: masterNotation()->excerpts()) {
if (excerpt->opened().val) {
m_notations << excerpt;
}
listenNotationOpeningStatus(excerpt);
}
endResetModel();
}
void NotationSwitchListModel::listenNotationOpeningStatus(INotationPtr notation)
{
notation->opened().ch.onReceive(this, [this, notation](bool opened) {
if (opened) {
beginInsertRows(QModelIndex(), m_notations.size(), m_notations.size());
m_notations << notation;
endInsertRows();
} else {
int notationIndex = m_notations.indexOf(notation);
beginRemoveRows(QModelIndex(), notationIndex, notationIndex);
m_notations.removeAt(notationIndex);
endRemoveRows();
}
});
}
IMasterNotationPtr NotationSwitchListModel::masterNotation() const
{
return context()->currentMasterNotation();
}
QVariant NotationSwitchListModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
@ -86,7 +132,7 @@ void NotationSwitchListModel::setCurrentNotation(int index)
return;
}
globalContext()->setCurrentNotation(m_notations[index]);
context()->setCurrentNotation(m_notations[index]);
}
void NotationSwitchListModel::closeNotation(int index)
@ -95,18 +141,16 @@ void NotationSwitchListModel::closeNotation(int index)
return;
}
if (globalContext()->currentNotation() == m_notations[index]) {
globalContext()->setCurrentNotation(nullptr);
INotationPtr notation = m_notations[index];
if (context()->currentNotation() == notation) {
context()->setCurrentNotation(nullptr);
}
beginRemoveRows(QModelIndex(), index, index);
m_notations.erase(m_notations.begin() + index);
endRemoveRows();
notation->setOpened(false);
}
bool NotationSwitchListModel::isIndexValid(int index) const
{
return index >= 0 && index < static_cast<int>(m_notations.size());
return index >= 0 && index < m_notations.size();
}

View file

@ -33,7 +33,7 @@ class NotationSwitchListModel : public QAbstractListModel, public async::Asyncab
{
Q_OBJECT
INJECT(notation, context::IGlobalContext, globalContext)
INJECT(notation, context::IGlobalContext, context)
public:
explicit NotationSwitchListModel(QObject* parent = nullptr);
@ -46,15 +46,21 @@ public:
Q_INVOKABLE void setCurrentNotation(int index);
Q_INVOKABLE void closeNotation(int index);
signals:
void currentNotationIndexChanged(int index);
private:
void updateNotations();
IMasterNotationPtr masterNotation() const;
void loadNotations();
void listenNotationOpeningStatus(INotationPtr notation);
bool isIndexValid(int index) const;
enum Roles {
RoleTitle = Qt::UserRole + 1,
};
std::vector<INotationPtr> m_notations;
QList<INotationPtr> m_notations;
QHash<int, QByteArray> m_roles;
};
}

View file

@ -19,7 +19,10 @@
#include "partlistmodel.h"
#include "iexcerptnotation.h"
#include "log.h"
#include "translation.h"
using namespace mu::notation;
@ -33,14 +36,7 @@ void PartListModel::load()
{
beginResetModel();
m_partsTitles = QStringList {
"Main Score",
"Flute",
"Bassoon",
"Horn in F",
"Trumpet",
"Piano"
};
m_excerpts = masterNotation()->excerpts();
endResetModel();
}
@ -53,7 +49,7 @@ QVariant PartListModel::data(const QModelIndex& index, int role) const
switch (role) {
case RoleTitle:
return m_partsTitles[index.row()];
return m_excerpts[index.row()]->metaInfo().title;
}
return QVariant();
@ -61,7 +57,7 @@ QVariant PartListModel::data(const QModelIndex& index, int role) const
int PartListModel::rowCount(const QModelIndex&) const
{
return m_partsTitles.count();
return m_excerpts.size();
}
QHash<int, QByteArray> PartListModel::roleNames() const
@ -71,16 +67,46 @@ QHash<int, QByteArray> PartListModel::roleNames() const
void PartListModel::createNewPart()
{
NOT_IMPLEMENTED;
Meta meta;
meta.title = qtrc("notation", "Part");
IExcerptNotationPtr excerpt = masterNotation()->appendExcerpt(meta);
excerpt->setOpened(true);
context()->setCurrentNotation(excerpt);
}
void PartListModel::openPart(int index)
void PartListModel::removeParts(const QModelIndexList& indexes)
{
Q_UNUSED(index)
NOT_IMPLEMENTED;
for (const QModelIndex& index: indexes) {
int row = index.row();
beginRemoveRows(QModelIndex(), row, row);
m_excerptsToRemove.push_back(m_excerpts[row]);
m_excerpts.erase(m_excerpts.begin() + row);
endRemoveRows();
}
}
void PartListModel::openAllParts()
void PartListModel::openParts(const QModelIndexList& indexes)
{
NOT_IMPLEMENTED;
if (indexes.isEmpty()) {
return;
}
for (const QModelIndex& index: indexes) {
m_excerpts[index.row()]->setOpened(true);
}
context()->setCurrentNotation(m_excerpts[indexes.last().row()]);
}
void PartListModel::apply()
{
for (IExcerptNotationPtr excerpt: m_excerptsToRemove) {
masterNotation()->removeExcerpt(excerpt);
}
}
IMasterNotationPtr PartListModel::masterNotation() const
{
return context()->currentMasterNotation();
}

View file

@ -22,11 +22,17 @@
#include <QAbstractListModel>
#include "modularity/ioc.h"
#include "context/iglobalcontext.h"
#include "iexcerptnotation.h"
namespace mu::notation {
class PartListModel : public QAbstractListModel
{
Q_OBJECT
INJECT(notation, context::IGlobalContext, context)
public:
explicit PartListModel(QObject* parent = nullptr);
@ -35,17 +41,21 @@ public:
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void load();
Q_INVOKABLE void createNewPart();
Q_INVOKABLE void openPart(int index);
Q_INVOKABLE void openAllParts();
Q_INVOKABLE void createNewPart();
Q_INVOKABLE void removeParts(const QModelIndexList& indexes);
Q_INVOKABLE void openParts(const QModelIndexList& indexes);
Q_INVOKABLE void apply();
private:
IMasterNotationPtr masterNotation() const;
enum Roles {
RoleTitle = Qt::UserRole + 1,
};
QHash<int, QByteArray> m_roles;
QStringList m_partsTitles;
std::vector<IExcerptNotationPtr> m_excerpts;
std::vector<IExcerptNotationPtr> m_excerptsToRemove;
};
}