class AbstractCommand : public QObject
{
    Q_OBJECT
public:
    explicit AbstractCommand(QObject* a_parent = nullptr);
    Q_INVOKABLE virtual void execute() = 0;
    virtual bool canExecute() const = 0;
signals:
    void canExecuteChanged( bool a_canExecute );
};

AbstractCommand::AbstractCommand(QObject *a_parent)
    : QObject( a_parent )
{
}

AbstractConfigurableCommand::AbstractConfigurableCommand(QObject *a_parent)
    :   AbstractCommand( a_parent )
    , m_canExecute( false ) { }

bool AbstractConfigurableCommand::canExecute() const
{
    return m_canExecute;
}
void AbstractConfigurableCommand::setCanExecute( bool a_canExecute )
{
    if( a_canExecute != m_canExecute ) {
        m_canExecute = a_canExecute;
        emit canExecuteChanged( m_canExecute );
        emit localCanExecuteChanged( m_canExecute );
    }
}

#include 

#include "CompositeCommand.h"

/*! \brief Constructor for a empty initial composite command */
CompositeCommand::CompositeCommand( QObject *a_parent )
    : AbstractCommand ( a_parent ) {}

/*! \brief Constructor for a list of members */
CompositeCommand::CompositeCommand( QList a_members, QObject *a_parent )
    : AbstractCommand ( a_parent )
{
    foreach (AbstractCommand* member, a_members) {
        registration(member);
        m_members.append( QSharedPointer(member) );
    }
}

/*! \brief Constructor for a list of members */
CompositeCommand::CompositeCommand( QList> a_members, QObject *a_parent )
    : AbstractCommand ( a_parent )
    , m_members ( a_members )
{
    foreach (const QSharedPointer& member, m_members) {
        registration(member.data());
    }
}

/*! \brief Destructor */
CompositeCommand::~CompositeCommand()
{
    foreach (const QSharedPointer& member, m_members) {
        deregistration(member.data());
    }
}

void CompositeCommand::executeAsync()
{
    foreach (const QSharedPointer& member, m_members) {
        member->executeAsync();
    }
}

bool CompositeCommand::canExecute() const
{
    foreach (const QSharedPointer& member, m_members) {
        if (!member->canExecute()) {
            return false;
        }
    }
    return true;
}

/*! \brief When one's canExecute changes */
void CompositeCommand::onCanExecuteChanged( bool a_canExecute )
{
    bool oldstate = !a_canExecute;
    bool newstate = a_canExecute;
    foreach (const QSharedPointer& member, m_members) {
        if ( member.data() != sender() ) {
            oldstate &= member->canExecute();
            newstate &= member->canExecute();
        }
    }

    if (oldstate != newstate) {
        emit canExecuteChanged( newstate );
    }
}

/*! \brief When one's execution completes */
void CompositeCommand::onExecutionCompleted( )
{
    m_completedCount++;

    if ( m_completedCount == m_members.count( ) ) {
        m_completedCount = 0;
        emit executionCompleted();
    }
}


void CompositeCommand::registration( AbstractCommand* a_member )
{
    connect( a_member, &AbstractCommand::canExecuteChanged,
             this, &CompositeCommand::onCanExecuteChanged );
    connect( a_member, &AbstractCommand::executionCompleted,
             this, &CompositeCommand::onExecutionCompleted );
}

void CompositeCommand::deregistration( AbstractCommand* a_member )
{
    disconnect( a_member, &AbstractCommand::canExecuteChanged,
                this, &CompositeCommand::onCanExecuteChanged );
    disconnect( a_member, &AbstractCommand::executionCompleted,
                this, &CompositeCommand::onExecutionCompleted );
}

void CompositeCommand::handleCanExecuteChanged(bool a_oldCanExecute)
{
    bool newCanExecute = canExecute();
    if( a_oldCanExecute != newCanExecute )
    {
        emit canExecuteChanged( newCanExecute );
    }
}

void CompositeCommand::add(AbstractCommand* a_member)
{
    bool oldCanExecute = canExecute();

    QQmlEngine::setObjectOwnership ( a_member, QQmlEngine::CppOwnership );
    m_members.append( QSharedPointer( a_member ) );
    registration ( a_member );

    handleCanExecuteChanged(oldCanExecute);
}

void CompositeCommand::add(const QSharedPointer& a_member)
{
    bool oldCanExecute = canExecute();

    m_members.append( a_member );
    registration ( a_member.data() );

    handleCanExecuteChanged(oldCanExecute);
}

void CompositeCommand::remove(AbstractCommand* a_member)
{
    bool oldCanExecute = canExecute();

    QMutableListIterator > i( m_members );
    while (i.hasNext()) {
        QSharedPointer val = i.next();
        if ( val.data() == a_member) {
            deregistration(val.data());
            i.remove();
        }
    }

    handleCanExecuteChanged(oldCanExecute);
}

void CompositeCommand::remove(const QSharedPointer& a_member)
{
    bool oldCanExecute = canExecute();

    deregistration(a_member.data());
    m_members.removeAll( a_member );

    handleCanExecuteChanged(oldCanExecute);
}

Leave a Reply

Your email address will not be published. Required fields are marked *