Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Model class visitable #4902

Merged
merged 6 commits into from
Apr 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions include/AutomatableModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand All @@ -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;
Expand All @@ -68,6 +74,7 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject
Q_OBJECT
MM_OPERATORS
public:

typedef QVector<AutomatableModel *> AutoModelVector;

enum ScaleType
Expand All @@ -80,6 +87,35 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject

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
Expand Down Expand Up @@ -283,6 +319,22 @@ public slots:


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 )
Expand Down Expand Up @@ -382,6 +434,7 @@ template <typename T> class LMMS_EXPORT TypedAutomatableModel : public Automatab
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,
Expand All @@ -399,6 +452,7 @@ class LMMS_EXPORT FloatModel : public TypedAutomatableModel<float>
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,
Expand All @@ -414,6 +468,7 @@ class LMMS_EXPORT IntModel : public TypedAutomatableModel<int>
class LMMS_EXPORT BoolModel : public TypedAutomatableModel<bool>
{
Q_OBJECT
MODEL_IS_VISITABLE
public:
BoolModel( const bool val = false,
Model* parent = NULL,
Expand Down
1 change: 1 addition & 0 deletions include/ComboBoxModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
class LMMS_EXPORT ComboBoxModel : public IntModel
{
Q_OBJECT
MODEL_IS_VISITABLE
public:
ComboBoxModel( Model* parent = NULL,
const QString& displayName = QString(),
Expand Down
64 changes: 64 additions & 0 deletions include/ModelVisitor.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions include/TempoSyncKnobModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class QAction;
class LMMS_EXPORT TempoSyncKnobModel : public FloatModel
{
Q_OBJECT
MODEL_IS_VISITABLE
public:
enum TempoSyncMode
{
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 44 additions & 0 deletions src/core/ModelVisitor.cpp
Original file line number Diff line number Diff line change
@@ -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() {}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ADD_EXECUTABLE(tests
QTestSuite
$<TARGET_OBJECTS:lmmsobjs>

src/core/AutomatableModelTest.cpp
src/core/ProjectVersionTest.cpp
src/core/RelativePathsTest.cpp

Expand Down
55 changes: 55 additions & 0 deletions tests/src/core/AutomatableModelTest.cpp
Original file line number Diff line number Diff line change
@@ -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"