/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "qfeedback.h" #include "connection_p.h" #include #include #include #include #include #include #include #include Q_EXPORT_PLUGIN2(feedback_simulator, QFeedbackSimulator) QFeedbackSimulator::QFeedbackSimulator() : QObject(qApp) , mDefaultActuator(-1) , mConnection(Simulator::Connection::instance()) { mConnection->connect(this); } QFeedbackSimulator::~QFeedbackSimulator() { } QFeedbackInterface::PluginPriority QFeedbackSimulator::pluginPriority() { return PluginNormalPriority; } QList QFeedbackSimulator::actuators() { return mActuatorList; } void QFeedbackSimulator::setActuatorProperty(const QFeedbackActuator &actuator, ActuatorProperty prop, const QVariant &value) { if (!mActuatorData.contains(actuator.id())) return; ActuatorData &data = mActuatorData[actuator.id()]; switch (prop) { case Enabled: data.enabled = value.toBool(); mConnection->setActuatorEnabled(actuator.id(), data.enabled); break; default: break; } } QVariant QFeedbackSimulator::actuatorProperty(const QFeedbackActuator &actuator, ActuatorProperty prop) { if (!mActuatorData.contains(actuator.id())) return QVariant(); const ActuatorData &data = mActuatorData.value(actuator.id()); switch (prop) { case Name: return data.name; case State: return data.state; case Enabled: return data.enabled; default: break; } return QVariant(); } bool QFeedbackSimulator::isActuatorCapabilitySupported(const QFeedbackActuator &, QFeedbackActuator::Capability) { return true; } static int totalEffectDuration(const QFeedbackHapticsEffect *effect) { if (effect->period() != -1) return QFeedbackEffect::Infinite; return effect->attackTime() + effect->duration() + effect->fadeTime(); } void QFeedbackSimulator::updateEffectProperty(const QFeedbackHapticsEffect *effect, EffectProperty property) { if (anyEffectState(effect) == QFeedbackEffect::Stopped || (property != AttackTime && property != Duration && property != FadeTime && property != Period)) { return; // nothing to do } int effectId = mEffectToId.value(effect, -1); if (effectId == -1) { reportError(effect, QFeedbackEffect::UnknownError); return; } mConnection->setEffectDuration(effectId, totalEffectDuration(effect)); } void QFeedbackSimulator::setEffectState(const QFeedbackHapticsEffect *effect, QFeedbackEffect::State state) { const int totalDuration = totalEffectDuration(effect); setAnyEffectState(effect, state, effect->actuator()->id(), totalDuration, tr("Custom haptics effect")); } QFeedbackEffect::State QFeedbackSimulator::effectState(const QFeedbackHapticsEffect *effect) { return anyEffectState(effect); } void QFeedbackSimulator::setLoaded(QFeedbackFileEffect *, bool) { } void QFeedbackSimulator::setEffectState(QFeedbackFileEffect *effect, QFeedbackEffect::State state) { setAnyEffectState(effect, state, mDefaultActuator, effect->duration(), tr("File: %1").arg(effect->source().toString())); } QFeedbackEffect::State QFeedbackSimulator::effectState(const QFeedbackFileEffect *effect) { return anyEffectState(effect); } int QFeedbackSimulator::effectDuration(const QFeedbackFileEffect *) { // ### Make configurable. return 2000; } QStringList QFeedbackSimulator::supportedMimeTypes() { return QStringList(); } bool QFeedbackSimulator::play(QFeedbackEffect::ThemeEffect theme) { if (mDefaultActuator == -1) return false; const QMetaEnum themeEnum = QFeedbackEffect::staticMetaObject.enumerator( QFeedbackEffect::staticMetaObject.indexOfEnumerator("ThemeEffect")); QString themeString = themeEnum.valueToKey(theme); int effectId = mConnection->startEffect(mDefaultActuator, themeString, 2000); if (effectId != -1) { mActuatorData[mDefaultActuator].state = QFeedbackActuator::Busy; return true; } return false; } void QFeedbackSimulator::setAnyEffectState(const QtMobility::QFeedbackEffect *effect, QFeedbackEffect::State state, int actuatorId, int duration, const QString &info) { if (actuatorId == -1) { reportError(effect, QFeedbackEffect::UnknownError); return; } const int effectId = mEffectToId.value(effect, -1); QFeedbackEffect::State old = anyEffectState(effect); switch (state) { case QFeedbackEffect::Running: { switch (old) { case QFeedbackEffect::Running: return; case QFeedbackEffect::Stopped: { int effectId = mConnection->startEffect(actuatorId, info, duration); if (effectId != -1) { mIdToEffect.insert(effectId, effect); mEffectToId.insert(effect, effectId); forceEffectState(effectId, state); mActuatorData[actuatorId].state = QFeedbackActuator::Busy; } else { reportError(effect, QFeedbackEffect::DeviceBusy); } return; } case QFeedbackEffect::Paused: { if (effectId != -1 && mConnection->resumeEffect(effectId)) { forceEffectState(effectId, state); } else { reportError(effect, QFeedbackEffect::UnknownError); } return; } case QFeedbackEffect::Loading: reportError(effect, QFeedbackEffect::UnknownError); return; } break; } case QFeedbackEffect::Paused: { switch (old) { case QFeedbackEffect::Paused: return; case QFeedbackEffect::Running: if (effectId != -1 && mConnection->pauseEffect(effectId)) { forceEffectState(effectId, state); } else { reportError(effect, QFeedbackEffect::UnknownError); } return; case QFeedbackEffect::Stopped: case QFeedbackEffect::Loading: reportError(effect, QFeedbackEffect::UnknownError); return; } break; } case QFeedbackEffect::Stopped: { switch (old) { case QFeedbackEffect::Stopped: return; case QFeedbackEffect::Running: case QFeedbackEffect::Paused: if (effectId != -1 && mConnection->stopEffect(effectId)) { forceEffectState(effectId, state); mActuatorData[actuatorId].state = QFeedbackActuator::Ready; } else { reportError(effect, QFeedbackEffect::UnknownError); } return; case QFeedbackEffect::Loading: reportError(effect, QFeedbackEffect::UnknownError); return; } break; } case QFeedbackEffect::Loading: { switch (old) { case QFeedbackEffect::Loading: return; case QFeedbackEffect::Stopped: forceEffectState(effectId, state); return; case QFeedbackEffect::Paused: case QFeedbackEffect::Running: reportError(effect, QFeedbackEffect::UnknownError); return; } break; } } } QFeedbackEffect::State QFeedbackSimulator::anyEffectState(const QtMobility::QFeedbackEffect *effect) { return mEffectStates.value(effect, QFeedbackEffect::Stopped); } void QFeedbackSimulator::forceEffectState(int effectId, QFeedbackEffect::State state) { const QFeedbackEffect *effect = mIdToEffect.value(effectId); if (!effect) return; if (state != QFeedbackEffect::Stopped) mEffectStates.insert(effect, state); else { mEffectStates.remove(effect); mEffectToId.remove(effect); mIdToEffect.remove(effectId); } } void QFeedbackSimulator::emitStateChanged(int effectId) { const QFeedbackEffect *effect = mIdToEffect.value(effectId); if (!effect) return; connect(this, SIGNAL(stateChangedProxySignal()), effect, SIGNAL(stateChanged())); emit stateChangedProxySignal(); disconnect(this, SIGNAL(stateChangedProxySignal()), effect, SIGNAL(stateChanged())); } void QFeedbackSimulator::setActuator(const QtMobility::ActuatorData &data) { mActuatorData.insert(data.id, data); if (!mActuators.contains(data.id)) { mActuators.insert(data.id, createFeedbackActuator(this, data.id)); rebuildActuatorList(); } } void QFeedbackSimulator::removeActuator(int id) { mActuatorData.remove(id); mActuators.remove(id); if (mDefaultActuator == id) mDefaultActuator = -1; rebuildActuatorList(); } void QFeedbackSimulator::rebuildActuatorList() { mActuatorList.clear(); if (mActuators.isEmpty()) return; // the first entry is the default actuator QFeedbackActuator *defaultActuator = 0; if (mDefaultActuator != -1) { defaultActuator = mActuators.value(mDefaultActuator); mActuatorList += defaultActuator; } foreach (QFeedbackActuator *actuator, mActuators) { if (actuator != defaultActuator) mActuatorList += actuator; } }