Merge pull request #4902 from JohannesLorenz/model-visitor
Make Model class visitable
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include "MidiTime.h"
|
||||
#include "ValueBuffer.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ModelVisitor.h"
|
||||
|
||||
// simple way to map a property of a view to a model
|
||||
#define mapPropertyFromModelPtr(type,getfunc,setfunc,modelname) \
|
||||
@@ -59,6 +60,11 @@
|
||||
modelname.setValue( (float) val ); \
|
||||
}
|
||||
|
||||
// use this to make subclasses visitable
|
||||
#define MODEL_IS_VISITABLE \
|
||||
void accept(ModelVisitor& v) override { v.visit(*this); } \
|
||||
void accept(ConstModelVisitor& v) const override { v.visit(*this); }
|
||||
|
||||
|
||||
|
||||
class ControllerConnection;
|
||||
@@ -68,6 +74,7 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject
|
||||
Q_OBJECT
|
||||
MM_OPERATORS
|
||||
public:
|
||||
|
||||
typedef QVector<AutomatableModel *> AutoModelVector;
|
||||
|
||||
enum ScaleType
|
||||
@@ -80,6 +87,35 @@ public:
|
||||
|
||||
virtual ~AutomatableModel();
|
||||
|
||||
// Implement those by using the MODEL_IS_VISITABLE macro
|
||||
virtual void accept(ModelVisitor& v) = 0;
|
||||
virtual void accept(ConstModelVisitor& v) const = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Return this class casted to Target
|
||||
@test AutomatableModelTest.cpp
|
||||
@param doThrow throw an assertion if the cast fails, instead of
|
||||
returning a nullptr
|
||||
@return the casted class if Target is the exact or a base class of
|
||||
*this, nullptr otherwise
|
||||
*/
|
||||
template<class Target>
|
||||
Target* dynamicCast(bool doThrow = false)
|
||||
{
|
||||
DCastVisitor<Target> vis; accept(vis);
|
||||
if (doThrow && !vis.result) { Q_ASSERT(false); }
|
||||
return vis.result;
|
||||
}
|
||||
|
||||
//! const overload, see overloaded function
|
||||
template<class Target>
|
||||
const Target* dynamicCast(bool doThrow = false) const
|
||||
{
|
||||
ConstDCastVisitor<Target> vis; accept(vis);
|
||||
if (doThrow && !vis.result) { Q_ASSERT(false); }
|
||||
return vis.result;
|
||||
}
|
||||
|
||||
bool isAutomated() const;
|
||||
bool isAutomatedOrControlled() const
|
||||
@@ -283,6 +319,22 @@ protected:
|
||||
|
||||
|
||||
private:
|
||||
// dynamicCast implementation
|
||||
template<class Target>
|
||||
struct DCastVisitor : public ModelVisitor
|
||||
{
|
||||
Target* result = nullptr;
|
||||
void visit(Target& tar) { result = &tar; }
|
||||
};
|
||||
|
||||
// dynamicCast implementation
|
||||
template<class Target>
|
||||
struct ConstDCastVisitor : public ConstModelVisitor
|
||||
{
|
||||
const Target* result = nullptr;
|
||||
void visit(const Target& tar) { result = &tar; }
|
||||
};
|
||||
|
||||
static bool mustQuoteName(const QString &name);
|
||||
|
||||
virtual void saveSettings( QDomDocument& doc, QDomElement& element )
|
||||
@@ -382,6 +434,7 @@ public:
|
||||
class LMMS_EXPORT FloatModel : public TypedAutomatableModel<float>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
FloatModel( float val = 0, float min = 0, float max = 0, float step = 0,
|
||||
Model * parent = NULL,
|
||||
@@ -399,6 +452,7 @@ public:
|
||||
class LMMS_EXPORT IntModel : public TypedAutomatableModel<int>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
IntModel( int val = 0, int min = 0, int max = 0,
|
||||
Model* parent = NULL,
|
||||
@@ -414,6 +468,7 @@ public:
|
||||
class LMMS_EXPORT BoolModel : public TypedAutomatableModel<bool>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
BoolModel( const bool val = false,
|
||||
Model* parent = NULL,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
class LMMS_EXPORT ComboBoxModel : public IntModel
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
ComboBoxModel( Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
|
||||
64
include/ModelVisitor.h
Normal file
64
include/ModelVisitor.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ModelVisitor.h - visitors for automatable models
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MODELVISITOR_H
|
||||
#define MODELVISITOR_H
|
||||
|
||||
class AutomatableModel;
|
||||
class BoolModel;
|
||||
class IntModel;
|
||||
class FloatModel;
|
||||
class ComboBoxModel;
|
||||
class TempoSyncKnobModel;
|
||||
|
||||
class ModelVisitor
|
||||
{
|
||||
template<class ParentType = AutomatableModel, class ModelType>
|
||||
void up(ModelType& m) { visit(static_cast<ParentType&>(m)); }
|
||||
public:
|
||||
virtual void visit(AutomatableModel& ) {}
|
||||
virtual void visit(BoolModel& m);
|
||||
virtual void visit(IntModel& m);
|
||||
virtual void visit(FloatModel& m);
|
||||
virtual void visit(ComboBoxModel& m);
|
||||
virtual void visit(TempoSyncKnobModel& m);
|
||||
virtual ~ModelVisitor();
|
||||
};
|
||||
|
||||
class ConstModelVisitor
|
||||
{
|
||||
template<class ParentType = AutomatableModel, class ModelType>
|
||||
void up(const ModelType& m) {
|
||||
visit(static_cast<const ParentType&>(m)); }
|
||||
public:
|
||||
virtual void visit(const AutomatableModel& ) {}
|
||||
virtual void visit(const BoolModel& m);
|
||||
virtual void visit(const IntModel& m);
|
||||
virtual void visit(const FloatModel& m);
|
||||
virtual void visit(const ComboBoxModel& m);
|
||||
virtual void visit(const TempoSyncKnobModel& m);
|
||||
virtual ~ConstModelVisitor();
|
||||
};
|
||||
|
||||
#endif // MODELVISITOR_H
|
||||
@@ -33,6 +33,7 @@ class QAction;
|
||||
class LMMS_EXPORT TempoSyncKnobModel : public FloatModel
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
enum TempoSyncMode
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ set(LMMS_SRCS
|
||||
core/MixerWorkerThread.cpp
|
||||
core/MixHelpers.cpp
|
||||
core/Model.cpp
|
||||
core/ModelVisitor.cpp
|
||||
core/Note.cpp
|
||||
core/NotePlayHandle.cpp
|
||||
core/Oscillator.cpp
|
||||
|
||||
44
src/core/ModelVisitor.cpp
Normal file
44
src/core/ModelVisitor.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ModelVisitor.cpp - visitors for automatable models
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* 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 "ModelVisitor.h"
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
#include "ComboBoxModel.h"
|
||||
#include "TempoSyncKnobModel.h"
|
||||
|
||||
void ModelVisitor::visit(BoolModel &m) { up(m); }
|
||||
void ModelVisitor::visit(IntModel &m) { up(m); }
|
||||
void ModelVisitor::visit(FloatModel &m) { up(m); }
|
||||
void ModelVisitor::visit(ComboBoxModel &m) { up<IntModel>(m); }
|
||||
void ModelVisitor::visit(TempoSyncKnobModel &m) { up<FloatModel>(m); }
|
||||
|
||||
void ConstModelVisitor::visit(const BoolModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const IntModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const FloatModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const ComboBoxModel &m) { up<IntModel>(m); }
|
||||
void ConstModelVisitor::visit(const TempoSyncKnobModel &m) { up<FloatModel>(m); }
|
||||
|
||||
ModelVisitor::~ModelVisitor() {}
|
||||
ConstModelVisitor::~ConstModelVisitor() {}
|
||||
@@ -14,6 +14,7 @@ ADD_EXECUTABLE(tests
|
||||
QTestSuite
|
||||
$<TARGET_OBJECTS:lmmsobjs>
|
||||
|
||||
src/core/AutomatableModelTest.cpp
|
||||
src/core/ProjectVersionTest.cpp
|
||||
src/core/RelativePathsTest.cpp
|
||||
|
||||
|
||||
55
tests/src/core/AutomatableModelTest.cpp
Normal file
55
tests/src/core/AutomatableModelTest.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* AutomatableModelTest.cpp
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* 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"
|
||||
#include "ComboBoxModel.h"
|
||||
|
||||
class AutomatableModelTest : QTestSuite
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
//! Test that upcast and exact casts work,
|
||||
//! but no downcast or any other casts
|
||||
void CastTests()
|
||||
{
|
||||
ComboBoxModel comboModel;
|
||||
AutomatableModel* amPtr = &comboModel;
|
||||
QVERIFY(nullptr == amPtr->dynamicCast<FloatModel>()); // not a parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<AutomatableModel>()); // parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<IntModel>()); // parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<ComboBoxModel>()); // same class
|
||||
|
||||
IntModel intModel;
|
||||
IntModel* imPtr = &intModel;
|
||||
QVERIFY(nullptr == imPtr->dynamicCast<FloatModel>()); // not a parent class
|
||||
QCOMPARE(&intModel, imPtr->dynamicCast<AutomatableModel>()); // parent class
|
||||
QCOMPARE(&intModel, imPtr->dynamicCast<IntModel>()); // same class
|
||||
QVERIFY(nullptr == imPtr->dynamicCast<ComboBoxModel>()); // child class
|
||||
}
|
||||
} AutomatableModelTests;
|
||||
|
||||
#include "AutomatableModelTest.moc"
|
||||
Reference in New Issue
Block a user