diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index cdfdffccf62..46a225189ed 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -220,6 +220,7 @@ class EXPORT AutomatableModel : public Model, public JournallingObject m_centerValue = centerVal; } + //! link @p m1 and @p m2, let @p m1 take the values of @p m2 static void linkModels( AutomatableModel* m1, AutomatableModel* m2 ); static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 ); @@ -325,7 +326,7 @@ public slots: DataType m_dataType; - ScaleType m_scaleType; //! scale type, linear by default + ScaleType m_scaleType; //!< scale type, linear by default float m_value; float m_initValue; float m_minValue; diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 5a97c328075..636a05ca99e 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -443,8 +443,24 @@ void AutomatableModel::unlinkModel( AutomatableModel* model ) void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 ) { + if (!model1->m_linkedModels.contains( model2 ) && model1 != model2) + { + // copy data + model1->m_value = model2->m_value; + if (model1->valueBuffer() && model2->valueBuffer()) + { + std::copy_n(model2->valueBuffer()->data(), + model1->valueBuffer()->length(), + model1->valueBuffer()->data()); + } + // send dataChanged() before linking (because linking will + // connect the two dataChanged() signals) + emit model1->dataChanged(); + // finally: link the models model1->linkModel( model2 ); model2->linkModel( model1 ); + } + emit model1->dataChanged(); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8cbe23858bf..ce0e00f4cd4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ ADD_EXECUTABLE(tests QTestSuite $ + src/core/AutomatableModelTest.cpp src/core/ProjectVersionTest.cpp src/core/RelativePathsTest.cpp diff --git a/tests/src/core/AutomatableModelTest.cpp b/tests/src/core/AutomatableModelTest.cpp new file mode 100644 index 00000000000..553656f8d3b --- /dev/null +++ b/tests/src/core/AutomatableModelTest.cpp @@ -0,0 +1,81 @@ +/* + * AutomatableModelTest.cpp + * + * Copyright (c) 2020 Johannes Lorenz + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "QTestSuite.h" + +#include "AutomatableModel.h" + +class AutomatableModelTest : QTestSuite +{ + Q_OBJECT + + bool m1Changed, m2Changed; + void resetChanged() { m1Changed = m2Changed = false; } + +private slots: // helper slots + void onM1Changed(Model* ) { m1Changed = true; } + void onM2Changed(Model* ) { m2Changed = true; } + +private slots: // tests + void LinkTests() + { + BoolModel m1(false), m2(false); + + QObject::connect(&m1, SIGNAL(dataChanged(Model*)), + this, SLOT(onM1Changed(Model*))); + QObject::connect(&m2, SIGNAL(dataChanged(Model*)), + this, SLOT(onM2Changed(Model*))); + + resetChanged(); + AutomatableModel::linkModels(&m1, &m1); + QVERIFY(!m1Changed); // cannot link to itself + QVERIFY(!m2Changed); + + resetChanged(); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(m1Changed); // since m1 takes the value of m2 + QVERIFY(!m2Changed); // the second model is the source + + resetChanged(); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(!m1Changed); // it's already linked + QVERIFY(!m2Changed); + + resetChanged(); + BoolModel m3(false); + m1.setValue(1.f); + m2.setValue(1.f); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(m1.value()); + QVERIFY(m2.value()); + QVERIFY(!m3.value()); + AutomatableModel::linkModels(&m2, &m3); // drag m3, drop on m2 + // m2 should take m3's (0) value + // due to a bug(?), this does not happen + QVERIFY(m2.value()); + QVERIFY(!m3.value()); + } +} AutomatableModelTests; + +#include "AutomatableModelTest.moc"