diff --git a/ground/openpilotgcs/src/plugins/notify/NotificationItem.h b/ground/openpilotgcs/src/plugins/notify/NotificationItem.h new file mode 100644 index 000000000..d4929a1e5 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/notify/NotificationItem.h @@ -0,0 +1,208 @@ +/** + ****************************************************************************** + * + * @file NotificationItem.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Notify Plugin configuration header + * @see The GNU Public License (GPL) Version 3 + * @defgroup notifyplugin + * @{ + * + *****************************************************************************/ +/* + * 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 3 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef NOTIFICATION_ITEM_H +#define NOTIFICATION_ITEM_H + +#include +#include "qsettings.h" +#include +#include + +using namespace Core; + +#define DECLARE_SOUND(number) \ + QString getSound##number() const { return _sound##number; } \ + void setSound##number(QString text) { _sound##number = text; } \ + +class UAVDataObject; +class UAVObjectField; + +class NotificationItem : public QObject +{ + Q_OBJECT +public: + enum { eDefaultTimeout = 15 }; // in sec + + explicit NotificationItem(QObject *parent = 0); + + void copyTo(NotificationItem*) const; + + DECLARE_SOUND(1) + DECLARE_SOUND(2) + DECLARE_SOUND(3) + + QString range() const { return _rangeLimit; } + void setRange(QString text) { _rangeLimit = text; } + + QString getSayOrder() const { return _sayOrder; } + void setSayOrder(QString text) { _sayOrder = text; } + + QVariant singleValue() const { return _singleValue; } + void setSingleValue(QVariant value) { _singleValue = value; } + + double valueRange2() const { return _valueRange2; } + void setValueRange2(double value) { _valueRange2 = value; } + + QString getDataObject() const { return _dataObject; } + void setDataObject(QString text) { _dataObject = text; } + + QString getObjectField() const { return _objectField; } + void setObjectField(QString text) { _objectField = text; } + + QString getSoundCollectionPath() const { return _soundCollectionPath; } + void setSoundCollectionPath(QString path) { _soundCollectionPath = path; } + + QString getCurrentLanguage() const { return _currentLanguage; } + void setCurrentLanguage(QString text) { _currentLanguage = text; } + + QStringList getMessageSequence() const { return _messageSequence; } + void setMessageSequence(QStringList sequence) { _messageSequence = sequence; } + + QString retryString() const { return _repeatString; } + void setRetryString(QString value) { _repeatString = value; } + + int lifetime() const { return _expireTimeout; } + void setLifetime(int value) { _expireTimeout = value; } + + bool mute() const { return _mute; } + void setMute(bool value) { _mute = value; } + + void saveState(QSettings* settings) const; + void restoreState(QSettings* settings); + + + UAVDataObject* getUAVObject(void); + UAVObjectField* getUAVObjectField(void); + + void seriaize(QDataStream& stream); + void deseriaize(QDataStream& stream); + + /** + * Convert notification item fields in single string, + * to show in table for example + * + * @return string which describe notification + */ + QString toString(); + + /** + * Generate list of sound files needed to play notification + * + * @return success - reference to non-empty _messageSequence; + * error - if one of sounds doesn't exist returns + * reference to empty _messageSequence; + */ + QStringList& toSoundList(); + + /** + * Returns sound caption name, needed to create string representation of notification. + * + * @return success - string == , if sound file exists + * error - string == [missind], if sound file doesn't exist + */ + QString getSoundCaption(QString fileName); + + + QTimer* getTimer() const { return _timer; } + void startTimer(int value); + void restartTimer(); + void stopTimer(); + void disposeTimer(); + + QTimer* getExpireTimer() const { return _expireTimer; } + void startExpireTimer(); + void stopExpireTimer(); + + void disposeExpireTimer(); + + bool isNowPlaying; + bool _isPlayed; + + static QStringList sayOrderValues; + static QStringList retryValues; + +private: + QString checkSoundExists(QString fileName); + +private: + + QTimer* _timer; + + //! time from putting notification in queue till moment when notification became out-of-date + //! NOTE: each notification has it lifetime, this time setups individually for each notification + //! according to its priority + QTimer* _expireTimer; + + //! list of wav files from which notification consists + QStringList _messageSequence; + + //! path to folder with sound files + QString _soundCollectionPath; + + //! language in what notifications will be spelled + QString _currentLanguage; + + //! one UAV object per one notification + QString _dataObject; + + //! one field value change can be assigned to one notification + QString _objectField; + + //! fire condition for UAV field value (lower, greater, in range) + QString _rangeLimit; + + //! possible sounds(at least one required to play notification) + QString _sound1; + QString _sound2; + QString _sound3; + + //! order in what sounds 1-3 will be played + QString _sayOrder; + + //! one-side range, value(numeric or ENUM type) maybe lower, greater or in range + QVariant _singleValue; + + //! both-side range, value should be inside the range + //double _valueRange1; + double _valueRange2; + + //! how often or what periodicaly notification should be played + QString _repeatString; + + //! time after event occured till notification became invalid + //! and will be removed from list + int _expireTimeout; + + //! enables/disables playing of current notification + bool _mute; +}; + +Q_DECLARE_METATYPE(NotificationItem*) + +#endif // NotificationItem_H diff --git a/ground/openpilotgcs/src/plugins/notify/notificationitem.cpp b/ground/openpilotgcs/src/plugins/notify/notificationitem.cpp new file mode 100644 index 000000000..ec86aabcd --- /dev/null +++ b/ground/openpilotgcs/src/plugins/notify/notificationitem.cpp @@ -0,0 +1,426 @@ +/** + ****************************************************************************** + * + * @file NotificationItem.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Notify Plugin configuration + * @see The GNU Public License (GPL) Version 3 + * @defgroup notifyplugin + * @{ + * + *****************************************************************************/ +/* + * 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 3 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//Qt headers +#include +#include + +// GCS headers +#include "extensionsystem/pluginmanager.h" +#include "utils/pathutils.h" +#include "uavobjectmanager.h" +#include "uavobject.h" + +// Notify plugin headers +#include "notificationitem.h" +#include "notifylogging.h" + + +static const QString cStrNever("Never"); +static const QString cStrBefore1st("Before first"); +static const QString cStrBefore2nd("Before second"); +static const QString cStrAfter2nd("After second"); + +static const QString cStrRetryOnce("Repeat Once"); +static const QString cStrRetryInstantly("Repeat Instantly"); +static const QString cStrRetry10sec("Repeat 10 seconds"); +static const QString cStrRetry30sec("Repeat 30 seconds"); +static const QString cStrRetry1min("Repeat 1 minute"); + + +QStringList NotificationItem::sayOrderValues; +QStringList NotificationItem::retryValues; + + +NotificationItem::NotificationItem(QObject *parent) + : QObject(parent) + , isNowPlaying(0) + , _isPlayed(false) + , _timer(NULL) + , _expireTimer(NULL) + , _soundCollectionPath("") + , _currentLanguage("default") + , _dataObject("") + , _objectField("") + , _rangeLimit("Equal to") + , _sound1("") + , _sound2("") + , _sound3("") + , _sayOrder(cStrNever) + , _singleValue(0) + , _valueRange2(0) + , _repeatString(cStrRetryInstantly) + , _expireTimeout(eDefaultTimeout) + , _mute(false) +{ + NotificationItem::sayOrderValues.clear(); + NotificationItem::sayOrderValues.append(cStrBefore1st); + NotificationItem::sayOrderValues.append(cStrBefore2nd); + NotificationItem::sayOrderValues.append(cStrAfter2nd); + + NotificationItem::retryValues.clear(); + NotificationItem::retryValues.append(cStrRetryOnce); + NotificationItem::retryValues.append(cStrRetryInstantly); + NotificationItem::retryValues.append(cStrRetry10sec); + NotificationItem::retryValues.append(cStrRetry30sec); + NotificationItem::retryValues.append(cStrRetry1min); + +} + +void NotificationItem::copyTo(NotificationItem* that) const +{ + that->isNowPlaying = isNowPlaying; + that->_isPlayed = _isPlayed; + that->_soundCollectionPath = _soundCollectionPath; + that->_currentLanguage = _currentLanguage; + that->_soundCollectionPath = _soundCollectionPath; + that->_dataObject = _dataObject; + that->_objectField = _objectField; + that->_rangeLimit = _rangeLimit; + that->_sound1 = _sound1; + that->_sound2 = _sound2; + that->_sound3 = _sound3; + that->_sayOrder = _sayOrder; + that->_singleValue = _singleValue; + that->_valueRange2 = _valueRange2; + that->_repeatString = _repeatString; + that->_expireTimeout = _expireTimeout; + that->_mute = _mute; + +} + + +void NotificationItem::saveState(QSettings* settings) const +{ + settings->setValue("SoundCollectionPath", Utils::PathUtils().RemoveDataPath(getSoundCollectionPath())); + settings->setValue(QLatin1String("CurrentLanguage"), getCurrentLanguage()); + settings->setValue(QLatin1String("ObjectField"), getObjectField()); + settings->setValue(QLatin1String("DataObject"), getDataObject()); + settings->setValue(QLatin1String("RangeLimit"), range()); + settings->setValue(QLatin1String("Value1"), singleValue()); + settings->setValue(QLatin1String("Value2"), valueRange2()); + settings->setValue(QLatin1String("Sound1"), getSound1()); + settings->setValue(QLatin1String("Sound2"), getSound2()); + settings->setValue(QLatin1String("Sound3"), getSound3()); + settings->setValue(QLatin1String("SayOrder"), getSayOrder()); + settings->setValue(QLatin1String("Repeat"), retryString()); + settings->setValue(QLatin1String("ExpireTimeout"), lifetime()); + settings->setValue(QLatin1String("Mute"), mute()); +} + +void NotificationItem::restoreState(QSettings* settings) +{ + //settings = Core::ICore::instance()->settings(); + setSoundCollectionPath(Utils::PathUtils().InsertDataPath(settings->value(QLatin1String("SoundCollectionPath"), tr("")).toString())); + setCurrentLanguage(settings->value(QLatin1String("CurrentLanguage"), tr("")).toString()); + setDataObject(settings->value(QLatin1String("DataObject"), tr("")).toString()); + setObjectField(settings->value(QLatin1String("ObjectField"), tr("")).toString()); + setRange(settings->value(QLatin1String("RangeLimit"), tr("")).toString()); + setSound1(settings->value(QLatin1String("Sound1"), tr("")).toString()); + setSound2(settings->value(QLatin1String("Sound2"), tr("")).toString()); + setSound3(settings->value(QLatin1String("Sound3"), tr("")).toString()); + setSayOrder(settings->value(QLatin1String("SayOrder"), tr("")).toString()); + QVariant value = settings->value(QLatin1String("Value1"), tr("")); + setSingleValue(value); + setValueRange2(settings->value(QLatin1String("Value2"), tr("")).toDouble()); + setRetryString(settings->value(QLatin1String("Repeat"), tr("")).toString()); + setLifetime(settings->value(QLatin1String("ExpireTimeout"), tr("")).toInt()); + setMute(settings->value(QLatin1String("Mute"), tr("")).toInt()); +} + +void NotificationItem::seriaize(QDataStream& stream) +{ + stream << this->_soundCollectionPath; + stream << this->_currentLanguage; + stream << this->_dataObject; + stream << this->_objectField; + stream << this->_rangeLimit; + stream << this->_sound1; + stream << this->_sound2; + stream << this->_sound3; + stream << this->_sayOrder; + stream << this->_singleValue; + stream << this->_valueRange2; + stream << this->_repeatString; + stream << this->_expireTimeout; + stream << this->_mute; +} + +void NotificationItem::deseriaize(QDataStream& stream) +{ + stream >> this->_soundCollectionPath; + stream >> this->_currentLanguage; + stream >> this->_dataObject; + stream >> this->_objectField; + stream >> this->_rangeLimit; + stream >> this->_sound1; + stream >> this->_sound2; + stream >> this->_sound3; + stream >> this->_sayOrder; + stream >> this->_singleValue; + stream >> this->_valueRange2; + stream >> this->_repeatString; + stream >> this->_expireTimeout; + stream >> this->_mute; +} + +void NotificationItem::startTimer(int msec) +{ + if (!_timer) { + _timer = new QTimer(this); + _timer->setInterval(msec); + } + if (!_timer->isActive()) + _timer->start(); +} + + +void NotificationItem::restartTimer() +{ + if (!_timer) { + if (!_timer->isActive()) + _timer->start(); + } +} + + +void NotificationItem::stopTimer() +{ + if (_timer) { + if (_timer->isActive()) + _timer->stop(); + } +} + +void NotificationItem::disposeTimer() +{ + if (_timer) { + _timer->stop(); + delete _timer; + _timer = NULL; + } +} + +void NotificationItem::startExpireTimer() +{ + if (!_expireTimer) { + _expireTimer = new QTimer(this); + } + _expireTimer->start(_expireTimeout * 1000); +} + +void NotificationItem::stopExpireTimer() +{ + if (_expireTimer) { + if (_expireTimer) + _expireTimer->stop(); + } +} + +void NotificationItem::disposeExpireTimer() +{ + if (_expireTimer) { + _expireTimer->stop(); + delete _expireTimer; + _expireTimer = NULL; + } +} + +int getValuePosition(QString sayOrder) +{ + return NotificationItem::sayOrderValues.indexOf(sayOrder); +} + +QString NotificationItem::checkSoundExists(QString fileName) +{ + QString name(fileName + ".wav"); + QString filePath = QDir::toNativeSeparators(getSoundCollectionPath() + "/" + + getCurrentLanguage() + "/" + + name); + if(QFile::exists(filePath)) + return filePath; + else { + filePath = QDir::toNativeSeparators(getSoundCollectionPath() + + "/default/" + + name); + if(!QFile::exists(filePath)) + filePath.clear(); + } + return filePath; +} + +QStringList valueToSoundList(QString value) +{ + // replace point chr if exists + value = value.replace(',', '.'); + QStringList numberParts = value.trimmed().split("."); + QStringList digitWavs; + + if ( (numberParts.at(0).size() == 1) || (numberParts.at(0).toInt() < 20) ) { + // [1] check, is this number < 20, these numbers played by one wav file + digitWavs.append(numberParts.at(0)); + } else { + int i=0; + // [2] store two lowest digits of number + int num = numberParts.at(0).right(2).toInt(); + if (num < 20 && num != 0) { + // store eighter number in range [0...10) or in range [10...20) + digitWavs.append(numberParts.at(0).right(1 + num/11)); + i=2; + } + // [3] prepend 100 and 1000 digits of number + for (;i number < 1 + digitWavs.append(numberParts.at(1)); + } else { + // append fractional part of number + QString left = numberParts.at(1).left(1); + (left == "0") ? digitWavs.append(left) : digitWavs.append(left + '0'); + digitWavs.append(numberParts.at(1).right(1)); + } + } + return digitWavs; +} + +QString stringFromValue(QVariant value, UAVObjectField* field) +{ + Q_ASSERT(field); + Q_ASSERT(!value.isNull()); + QString str; + if (UAVObjectField::ENUM == field->getType()) { + if(!field->getOptions().contains(value.toString())) + return QString(); + str = value.toString(); + } else { + str = QString("%L1").arg(value.toDouble()); + } + return str; +} + +QString NotificationItem::toString() +{ + QString str; + UAVObjectField* field = getUAVObjectField(); + QString value = stringFromValue(singleValue(), field); + + int pos = getValuePosition(getSayOrder().trimmed()); + QStringList lst; + lst.append(getSoundCaption(getSound1())); + lst.append(getSoundCaption(getSound2())); + lst.append(getSoundCaption(getSound3())); + QStringList valueSounds = valueToSoundList(value); + bool missed = false; + foreach(QString sound, valueSounds) { + if(checkSoundExists(sound).isEmpty()) { + missed = true; + break; + } + } + + // if not "Never" case + if(-1 != pos) { + if(missed) + lst.insert(pos, "[missed]" + value); + else + lst.insert(pos, value); + } + str = lst.join(" "); + return str; +} + +QStringList& NotificationItem::toSoundList() +{ + // tips: + // check of *.wav files exist needed for playing phonon queues; + // if phonon player don't find next file in queue, it buzz + UAVObjectField* field = getUAVObjectField(); + QString value = stringFromValue(singleValue(), field); + + // generate queue of sound files to play + _messageSequence.clear(); + int pos = getValuePosition(getSayOrder().trimmed()); + QStringList lst; + if(!getSound1().isEmpty()) + lst.append(getSound1()); + if(!getSound2().isEmpty()) + lst.append(getSound2()); + if(!getSound3().isEmpty()) + lst.append(getSound3()); + + // if not "Never" case + if(-1 != pos) { + QStringList valueSounds = valueToSoundList(value); + foreach(QString sound, valueSounds) + lst.insert(pos++, sound); + } + + foreach(QString sound, lst) { + QString path = checkSoundExists(sound); + if (!path.isEmpty()) { + _messageSequence.append(path); + } else { + _messageSequence.clear(); + break; + } + } + return _messageSequence; +} + +QString NotificationItem::getSoundCaption(QString fileName) +{ + if(fileName.isEmpty()) return QString(); + if(checkSoundExists(fileName).isEmpty()) { + return QString("[missed]") + fileName; + } + return fileName; +} + +UAVObjectField* NotificationItem::getUAVObjectField() { + return getUAVObject()->getField(getObjectField()); +} + +UAVDataObject* NotificationItem::getUAVObject() { + return dynamic_cast((ExtensionSystem::PluginManager::instance()->getObject())->getObject(getDataObject())); +} diff --git a/ground/openpilotgcs/src/plugins/notify/notify.pro b/ground/openpilotgcs/src/plugins/notify/notify.pro index 9ebebfa22..fca92db99 100644 --- a/ground/openpilotgcs/src/plugins/notify/notify.pro +++ b/ground/openpilotgcs/src/plugins/notify/notify.pro @@ -10,15 +10,17 @@ QT += phonon HEADERS += notifyplugin.h \ notifypluginoptionspage.h \ - notifypluginconfiguration.h \ notifyitemdelegate.h \ - notifytablemodel.h + notifytablemodel.h \ + notificationitem.h \ + notifylogging.h SOURCES += notifyplugin.cpp \ notifypluginoptionspage.cpp \ - notifypluginconfiguration.cpp \ notifyitemdelegate.cpp \ - notifytablemodel.cpp + notifytablemodel.cpp \ + notificationitem.cpp \ + notifylogging.cpp OTHER_FILES += NotifyPlugin.pluginspec @@ -27,3 +29,5 @@ FORMS += \ RESOURCES += \ res.qrc + + diff --git a/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.cpp b/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.cpp index 7a2fc2ef4..da7177b35 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.cpp +++ b/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.cpp @@ -25,136 +25,132 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "notifyitemdelegate.h" #include +#include "notifyitemdelegate.h" +#include "notifytablemodel.h" +#include "notifylogging.h" +#include "notificationitem.h" - - NotifyItemDelegate::NotifyItemDelegate(QStringList items,QObject *parent) - : QItemDelegate(parent), - m_parent(parent), - m_items(items) { - - } - - QWidget *NotifyItemDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem &, - const QModelIndex &index) const - { - if (index.column() == 1) { - QComboBox* editor = new QComboBox(parent); - editor->clear(); - editor->addItems(m_items); - //repeatEditor->setCurrentIndex(0); - //repeatEditor->setItemDelegate(new RepeatCounterDelegate()); - - //connect(repeatEditor,SIGNAL(activated (const QString& )),this,SLOT(selectRow(const QString& ))); - //QTableWidgetItem* item = qobject_cast(parent); - //((QTableWidgetItem*)parent)->setSelected(true); -// connect(editor, SIGNAL(editingFinished()), -// this, SLOT(commitAndCloseEditor())); - return editor; - } else - { - if(index.column() == 2) - { - QSpinBox* editor = new QSpinBox(parent); - connect(editor, SIGNAL(editingFinished()), - this, SLOT(commitAndCloseEditor())); - return editor; - } - - } - QLineEdit *editor = new QLineEdit(parent); -// connect(editor, SIGNAL(editingFinished()), -// this, SLOT(commitAndCloseEditor())); - return editor; - } - - void NotifyItemDelegate::commitAndCloseEditor() - { - QLineEdit *editor = qobject_cast(sender()); - if (editor) - { - emit commitData(editor); - emit closeEditor(editor); - - } else { - QComboBox* editor = qobject_cast(sender()); - if (editor) - { - emit commitData(editor); - emit closeEditor(editor); - } else { - QSpinBox* editor = qobject_cast(sender()); - if (editor) - { - emit commitData(editor); - emit closeEditor(editor); - } - } - } - } - - void NotifyItemDelegate::setEditorData(QWidget *editor, - const QModelIndex &index) const - { - QLineEdit *edit = qobject_cast(editor); - if (edit) { - edit->setText(index.model()->data(index, Qt::EditRole).toString()); - } else { - QComboBox * repeatEditor = qobject_cast(editor); - if (repeatEditor) - repeatEditor->setCurrentIndex(repeatEditor->findText(index.model()->data(index, Qt::EditRole).toString())); - else { - QSpinBox * expireEditor = qobject_cast(editor); - if (expireEditor) - expireEditor->setValue(index.model()->data(index, Qt::EditRole).toInt()); - } - } - } - - void NotifyItemDelegate::setModelData(QWidget *editor, - QAbstractItemModel *model, const QModelIndex &index) const - { - QLineEdit *edit = qobject_cast(editor); - if (edit) { - model->setData(index, edit->text()); - } else { - QComboBox * repeatEditor = qobject_cast(editor); - if (repeatEditor) { - model->setData(index, repeatEditor->currentText()); - - } else { - QSpinBox * expireEditor = qobject_cast(editor); - if (expireEditor) { - //expireEditor->interpretText(); - model->setData(index, expireEditor->value(), Qt::EditRole); - } - } - } - } - - -void NotifyItemDelegate::selectRow(const QString & text) +NotifyItemDelegate::NotifyItemDelegate(QObject* parent) + : QItemDelegate(parent) + , _parent(parent) { - //QList list = ((QTableWidget*)(sender()->parent()))->findItems(text,Qt::MatchExactly); - QComboBox* combo = qobject_cast(sender()); - QTableWidget* table = new QTableWidget; - table = (QTableWidget*)(combo->parent()); - qDebug()<columnCount(); - qDebug()<rowCount(); - qDebug()<currentRow(); - //table->setCurrentIndex(1); - //table->findItems(text,Qt::MatchExactly); - //item->model()->index() - //item->setSelected(true); } -QSize NotifyItemDelegate::sizeHint ( const QStyleOptionViewItem & option, - const QModelIndex & index ) const +QWidget *NotifyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& /*none*/, + const QModelIndex& index) const { - QSize s = QItemDelegate::sizeHint(option, index); - s.setHeight(10); - - return s; + if (eRepeatValue == index.column()) { + QComboBox* editor = new QComboBox(parent); + editor->clear(); + editor->addItems(NotificationItem::retryValues); + return editor; + } else { + if (eExpireTimer == index.column()) { + QSpinBox* editor = new QSpinBox(parent); + connect(editor, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor())); + return editor; + } else { + if (eTurnOn == index.column()) { + QCheckBox* editor = new QCheckBox(parent); + connect(editor, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor())); + return editor; + } + } + } + QLineEdit *editor = new QLineEdit(parent); + return editor; +} + +void NotifyItemDelegate::commitAndCloseEditor() +{ + QLineEdit* editor = qobject_cast(sender()); + if (editor) { + emit commitData(editor); + emit closeEditor(editor); + } else { + QComboBox* editor = qobject_cast(sender()); + if (editor) + { + emit commitData(editor); + emit closeEditor(editor); + } else { + QSpinBox* editor = qobject_cast(sender()); + if (editor) + { + emit commitData(editor); + emit closeEditor(editor); + } else { + QCheckBox* editor = qobject_cast(sender()); + if (editor) + { + emit commitData(editor); + emit closeEditor(editor); + } + } + } + } +} + +void NotifyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QLineEdit* edit = qobject_cast(editor); + if (edit) { + edit->setText(index.model()->data(index, Qt::EditRole).toString()); + } else { + QComboBox* repeatEditor = qobject_cast(editor); + if (repeatEditor) + repeatEditor->setCurrentIndex(repeatEditor->findText(index.model()->data(index, Qt::EditRole).toString())); + else { + QSpinBox* expireEditor = qobject_cast(editor); + if (expireEditor) + expireEditor->setValue(index.model()->data(index, Qt::EditRole).toInt()); + else { + QCheckBox* enablePlayEditor = qobject_cast(editor); + if (enablePlayEditor) + enablePlayEditor->setChecked(index.model()->data(index, Qt::EditRole).toBool()); + } + } + } +} + +void NotifyItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const +{ + QLineEdit *edit = qobject_cast(editor); + if (edit) { + model->setData(index, edit->text()); + } else { + QComboBox * repeatEditor = qobject_cast(editor); + if (repeatEditor) { + model->setData(index, repeatEditor->currentText()); + } else { + QSpinBox * expireEditor = qobject_cast(editor); + if (expireEditor) { + model->setData(index, expireEditor->value(), Qt::EditRole); + } else { + QCheckBox* enablePlayEditor = qobject_cast(editor); + if (enablePlayEditor) { + model->setData(index, enablePlayEditor->isChecked(), Qt::EditRole); + } + } + } + } +} + +void NotifyItemDelegate::selectRow(const QString& text) +{ + QComboBox* combo = qobject_cast(sender()); + QTableWidget* table = new QTableWidget; + table = (QTableWidget*)(combo->parent()); + + qNotifyDebug() << table->columnCount(); + qNotifyDebug() << table->rowCount(); + qNotifyDebug() << table->currentRow(); +} + +QSize NotifyItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QSize s = QItemDelegate::sizeHint(option, index); + s.setHeight(10); + return s; } diff --git a/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.h b/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.h index 40d6ced20..ace6d4976 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.h +++ b/ground/openpilotgcs/src/plugins/notify/notifyitemdelegate.h @@ -31,46 +31,26 @@ #include #include -//class RepeatCounterDelegate : public QItemDelegate -//{ -// Q_OBJECT - -//public: -// RepeatCounterDelegate(QObject *parent = 0); -// QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, -// const QModelIndex &index) const; -// void setEditorData(QWidget *editor, const QModelIndex &index) const; -// void setModelData(QWidget *editor, QAbstractItemModel *model, -// const QModelIndex &index) const; - -//private slots: -// void commitAndCloseEditor(); -//}; class NotifyItemDelegate : public QItemDelegate { - Q_OBJECT + Q_OBJECT public: - NotifyItemDelegate(QStringList items, QObject *parent = 0); - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, - const QModelIndex &index) const; - void setEditorData(QWidget *editor, const QModelIndex &index) const; - void setModelData(QWidget *editor, QAbstractItemModel *model, - const QModelIndex &index) const; -// bool editorEvent(QEvent * event, QAbstractItemModel * model, -// const QStyleOptionViewItem & option, const QModelIndex & index ); - QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const; - -private: - QObject* m_parent; - QStringList m_items; - QComboBox* repeatEditor; - + NotifyItemDelegate(QObject *parent = 0); + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &index) const; + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const; private slots: - void selectRow(const QString & text); - void commitAndCloseEditor(); + void selectRow(const QString & text); + void commitAndCloseEditor(); + +private: + QObject* _parent; }; #endif // NOTIFYITEMDELEGATE_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifylogging.cpp b/ground/openpilotgcs/src/plugins/notify/notifylogging.cpp new file mode 100644 index 000000000..3cb11d111 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/notify/notifylogging.cpp @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * + * @file notifylogging.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Uses to logging only inside notify plugin, + * can be convinient turned on/off + * @see The GNU Public License (GPL) Version 3 + * @defgroup notifyplugin + * @{ + * + *****************************************************************************/ +/* + * 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 3 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "notifylogging.h" + +#ifdef DEBUG_NOTIFIES_ENABLE +QDebug qNotifyDebug() +{ + return qDebug() << "[NOTIFY_PLG]"; +} +#endif + +#ifndef DEBUG_NOTIFIES_ENABLE +QNoDebug qNotifyDebug() +{ + return QNoDebug(); +} +#endif diff --git a/ground/openpilotgcs/src/plugins/notify/notifylogging.h b/ground/openpilotgcs/src/plugins/notify/notifylogging.h new file mode 100644 index 000000000..ea7ea331c --- /dev/null +++ b/ground/openpilotgcs/src/plugins/notify/notifylogging.h @@ -0,0 +1,46 @@ +/** + ****************************************************************************** + * + * @file notifylogging.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Uses to logging only inside notify plugin, + * can be convinient turned on/off + * @see The GNU Public License (GPL) Version 3 + * @defgroup notifyplugin + * @{ + * + *****************************************************************************/ +/* + * 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 3 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NOTIFYLOGGING_H +#define NOTIFYLOGGING_H + +#include "QDebug.h" + +#define DEBUG_NOTIFIES_ENABLE + +#ifdef DEBUG_NOTIFIES_ENABLE +QDebug qNotifyDebug(); +#endif + +#ifndef DEBUG_NOTIFIES_ENABLE +QNoDebug qNotifyDebug(); +#endif + +#define qNotifyDebug_if(test) if(test) qNotifyDebug() + +#endif // NOTIFYLOGGING_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifyplugin.cpp b/ground/openpilotgcs/src/plugins/notify/notifyplugin.cpp index 8735f8b60..5ac05776a 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifyplugin.cpp +++ b/ground/openpilotgcs/src/plugins/notify/notifyplugin.cpp @@ -26,8 +26,9 @@ */ #include "notifyplugin.h" -#include "notifypluginconfiguration.h" +#include "notificationitem.h" #include "notifypluginoptionspage.h" +#include "notifylogging.h" #include #include #include @@ -37,16 +38,16 @@ #include #include "qxttimer.h" +#include "backendcapabilities.h" static const QString VERSION = "1.0.0"; //#define DEBUG_NOTIFIES + SoundNotifyPlugin::SoundNotifyPlugin() { - phonon.mo = NULL; - configured = false; - // Do nothing + phonon.mo = NULL; } SoundNotifyPlugin::~SoundNotifyPlugin() @@ -54,7 +55,6 @@ SoundNotifyPlugin::~SoundNotifyPlugin() Core::ICore::instance()->saveSettings(this); if (phonon.mo != NULL) delete phonon.mo; - // Do nothing } bool SoundNotifyPlugin::initialize(const QStringList& args, QString *errMsg) @@ -70,15 +70,12 @@ bool SoundNotifyPlugin::initialize(const QStringList& args, QString *errMsg) void SoundNotifyPlugin::extensionsInitialized() { - Core::ICore::instance()->readSettings(this); - if ( !configured ){ - readConfig_0_0_0(); - } + Core::ICore::instance()->readSettings(this); - ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); - connect(pm, SIGNAL(objectAdded(QObject*)), this, SLOT(onTelemetryManagerAdded(QObject*))); - removedNotifies.clear(); - connectNotifications(); + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + connect(pm, SIGNAL(objectAdded(QObject*)), this, SLOT(onTelemetryManagerAdded(QObject*))); + _toRemoveNotifications.clear(); + connectNotifications(); } void SoundNotifyPlugin::saveConfig( QSettings* settings, UAVConfigInfo *configInfo){ @@ -95,22 +92,19 @@ void SoundNotifyPlugin::saveConfig( QSettings* settings, UAVConfigInfo *configIn settings->endGroup(); settings->beginWriteArray("listNotifies"); - for (int i = 0; i < lstNotifications.size(); i++) { - settings->setArrayIndex(i); - lstNotifications.at(i)->saveState(settings); + for (int i = 0; i < _notificationList.size(); i++) { + settings->setArrayIndex(i); + _notificationList.at(i)->saveState(settings); } settings->endArray(); settings->setValue(QLatin1String("EnableSound"), enableSound); } -void SoundNotifyPlugin::readConfig( QSettings* settings, UAVConfigInfo *configInfo){ - - if ( configInfo->version() == UAVConfigVersion() ){ - // Just for migration to the new format. - configured = false; - return; - } +void SoundNotifyPlugin::readConfig( QSettings* settings, UAVConfigInfo *configInfo) +{ + // Just for migration to the new format. + //Q_ASSERT(configInfo->version() == UAVConfigVersion()); settings->beginReadArray("Current"); settings->setArrayIndex(0); @@ -120,52 +114,20 @@ void SoundNotifyPlugin::readConfig( QSettings* settings, UAVConfigInfo *configIn // read list of notifications from settings int size = settings->beginReadArray("listNotifies"); for (int i = 0; i < size; ++i) { - settings->setArrayIndex(i); - NotifyPluginConfiguration* notification = new NotifyPluginConfiguration; - notification->restoreState(settings); - lstNotifications.append(notification); + settings->setArrayIndex(i); + NotificationItem* notification = new NotificationItem; + notification->restoreState(settings); + _notificationList.append(notification); } settings->endArray(); setEnableSound(settings->value(QLatin1String("EnableSound"),0).toBool()); - - configured = true; } -void SoundNotifyPlugin::readConfig_0_0_0(){ - - settings = Core::ICore::instance()->settings(); - settings->beginGroup(QLatin1String("NotifyPlugin")); - - settings->beginReadArray("Current"); - settings->setArrayIndex(0); - currentNotification.restoreState(settings); - settings->endArray(); - - // read list of notifications from settings - int size = settings->beginReadArray("listNotifies"); - for (int i = 0; i < size; ++i) { - settings->setArrayIndex(i); - NotifyPluginConfiguration* notification = new NotifyPluginConfiguration; - notification->restoreState(settings); - lstNotifications.append(notification); - } - settings->endArray(); - setEnableSound(settings->value(QLatin1String("EnableSound"),0).toBool()); - settings->endGroup(); - - ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); - connect(pm, SIGNAL(objectAdded(QObject*)), this, SLOT(onTelemetryManagerAdded(QObject*))); - removedNotifies.clear(); - connectNotifications(); - - configured = true; - } - void SoundNotifyPlugin::onTelemetryManagerAdded(QObject* obj) { - telMngr = qobject_cast(obj); - if(telMngr) - connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect())); + telMngr = qobject_cast(obj); + if (telMngr) + connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect())); } void SoundNotifyPlugin::shutdown() @@ -175,340 +137,382 @@ void SoundNotifyPlugin::shutdown() void SoundNotifyPlugin::onAutopilotDisconnect() { - connectNotifications(); + connectNotifications(); } /*! - clear any notify timers from previous flight; - reset will be perform on start of option page + clear any notify timers from previous flight; + reset will be perform on start of option page */ void SoundNotifyPlugin::resetNotification(void) { - //first, reject empty args and unknown fields. - foreach(NotifyPluginConfiguration* notify,lstNotifications) { - if(notify->timer) - { - disconnect(notify->timer, SIGNAL(timeout()), this, SLOT(repeatTimerHandler())); - notify->timer->stop(); - delete notify->timer; - notify->timer = NULL; - } - if(notify->expireTimer) - { - disconnect(notify->expireTimer, SIGNAL(timeout()), this, SLOT(expireTimerHandler())); - notify->expireTimer->stop(); - delete notify->expireTimer; - notify->expireTimer = NULL; - } - } + //first, reject empty args and unknown fields. + foreach(NotificationItem* ntf, _notificationList) { + ntf->disposeTimer(); + disconnect(ntf->getTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification())); + ntf->disposeExpireTimer(); + disconnect(ntf->getExpireTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification())); + } } /*! - update list of notifies; - will be perform on OK or APPLY press of option page + update list of notifies; + will be perform on OK or APPLY press of option page */ -void SoundNotifyPlugin::updateNotificationList(QList list) +void SoundNotifyPlugin::updateNotificationList(QList list) { - removedNotifies.clear(); - resetNotification(); - lstNotifications.clear(); - lstNotifications=list; - connectNotifications(); + _toRemoveNotifications.clear(); + resetNotification(); + _notificationList.clear(); + _notificationList=list; + connectNotifications(); - Core::ICore::instance()->saveSettings(this); + Core::ICore::instance()->saveSettings(this); } void SoundNotifyPlugin::connectNotifications() { - foreach(UAVDataObject* obj,lstNotifiedUAVObjects) { - if (obj != NULL) - disconnect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(appendNotification(UAVObject*))); - } - if(phonon.mo != NULL) { - delete phonon.mo; - phonon.mo = NULL; + foreach(UAVDataObject* obj,lstNotifiedUAVObjects) { + if (obj != NULL) + disconnect(obj,SIGNAL(objectUpdated(UAVObject*)),this,SLOT(on_arrived_Notification(UAVObject*))); + } + if (phonon.mo != NULL) { + delete phonon.mo; + phonon.mo = NULL; + } + + if (!enableSound) return; + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + + lstNotifiedUAVObjects.clear(); + _pendingNotifications.clear(); + _notificationList.append(_toRemoveNotifications); + _toRemoveNotifications.clear(); + + //first, reject empty args and unknown fields. + foreach(NotificationItem* notify, _notificationList) { + notify->_isPlayed = false; + notify->isNowPlaying=false; + + if(notify->mute()) continue; + // check is all sounds presented for notification, + // if not - we must not subscribe to it at all + if(notify->toSoundList().isEmpty()) continue; + + UAVDataObject* obj = dynamic_cast( objManager->getObject(notify->getDataObject()) ); + if (obj != NULL ) { + if (!lstNotifiedUAVObjects.contains(obj)) { + lstNotifiedUAVObjects.append(obj); + + connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(on_arrived_Notification(UAVObject*))); + } + } else { + qNotifyDebug() << "Error: Object is unknown (" << notify->getDataObject() << ")."; } + } - if(!enableSound) return; - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - - lstNotifiedUAVObjects.clear(); - pendingNotifications.clear(); - lstNotifications.append(removedNotifies); - removedNotifies.clear(); - - //first, reject empty args and unknown fields. - foreach(NotifyPluginConfiguration* notify,lstNotifications) { - notify->firstStart=true; - notify->isNowPlaying=false; - -// if(notify->timer) -// { -// disconnect(notify->timer, SIGNAL(timeout()), this, SLOT(repeatTimerHandler())); -// notify->timer->stop(); -// delete notify->timer; -// notify->timer = NULL; -// } -// if(notify->expireTimer) -// { -// disconnect(notify->expireTimer, SIGNAL(timeout()), this, SLOT(expireTimerHandler())); -// notify->expireTimer->stop(); -// delete notify->expireTimer; -// notify->expireTimer = NULL; -// } - - UAVDataObject* obj = dynamic_cast( objManager->getObject(notify->getDataObject()) ); - if (obj != NULL ) { - if(!lstNotifiedUAVObjects.contains(obj)) { - lstNotifiedUAVObjects.append(obj); - connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(appendNotification(UAVObject*))); - } - } else - std::cout << "Error: Object is unknown (" << notify->getDataObject().toStdString() << ")." << std::endl; - } - - if(lstNotifications.isEmpty()) return; - // set notification message to current event - phonon.mo = Phonon::createPlayer(Phonon::NotificationCategory); - phonon.mo->clearQueue(); - phonon.firstPlay = true; -#ifdef DEBUG_NOTIFIES - QList audioOutputDevices = - Phonon::BackendCapabilities::availableAudioOutputDevices(); - foreach(Phonon::AudioOutputDevice dev, audioOutputDevices) { - qDebug() << "Notify: Audio Output device: " << dev.name() << " - " << dev.description(); - } -#endif - connect(phonon.mo,SIGNAL(stateChanged(Phonon::State,Phonon::State)), - this,SLOT(stateChanged(Phonon::State,Phonon::State))); + if (_notificationList.isEmpty()) return; + // set notification message to current event + phonon.mo = Phonon::createPlayer(Phonon::NotificationCategory); + phonon.mo->clearQueue(); + phonon.firstPlay = true; + QList audioOutputDevices = + Phonon::BackendCapabilities::availableAudioOutputDevices(); + foreach(Phonon::AudioOutputDevice dev, audioOutputDevices) { + qNotifyDebug() << "Notify: Audio Output device: " << dev.name() << " - " << dev.description(); + } + connect(phonon.mo, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this, SLOT(stateChanged(Phonon::State,Phonon::State))); } -void SoundNotifyPlugin::appendNotification(UAVObject *object) +void SoundNotifyPlugin::on_arrived_Notification(UAVObject *object) { - disconnect(object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(appendNotification(UAVObject*))); + foreach(NotificationItem* ntf, _notificationList) { + if (object->getName() != ntf->getDataObject()) + continue; - foreach(NotifyPluginConfiguration* notification, lstNotifications) { - if(object->getName()!=notification->getDataObject()) - continue; - if(nowPlayingConfiguration == notification) - continue; + // skip duplicate notifications + if (_nowPlayingNotification == ntf) + continue; - if(notification->getRepeatFlag()!= "Repeat Instantly" && - notification->getRepeatFlag()!= "Repeat Once" && !notification->firstStart) - continue; + // skip periodical notifications + // this condition accepts: + // 1. Periodical notifications played firstly; + // NOTE: At first time it will be played, then it played only by timer, + // when conditions became false firstStart flag has been cleared and + // notification can be accepted again; + // 2. Once time notifications, they removed immediately after first playing; + // 3. Instant notifications(played one by one without interval); + if (ntf->retryString() != "Repeat Instantly" && + ntf->retryString() != "Repeat Once" && ntf->_isPlayed) + continue; - checkNotificationRule(notification,object); - } - connect(object, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(appendNotification(UAVObject*))); + qNotifyDebug() << QString("new notification: | %1 | %2 | val1: %3 | val2: %4") + .arg(ntf->getDataObject()) + .arg(ntf->getObjectField()) + .arg(ntf->singleValue().toString()) + .arg(ntf->valueRange2()); + + QString fieldName = ntf->getObjectField(); + UAVObjectField* field = object->getField(fieldName); + + qNotifyDebug() << QString("UAV object: %1 | value: %2") + .arg(object->getName()) + .arg(field->getValue().toString()); + + checkNotificationRule(ntf, object); + } + connect(object, SIGNAL(objectUpdated(UAVObject*)), + this, SLOT(on_arrived_Notification(UAVObject*)), Qt::UniqueConnection); } -void SoundNotifyPlugin::checkNotificationRule(NotifyPluginConfiguration* notification, UAVObject* object) +void SoundNotifyPlugin::on_timerRepeated_Notification() { - bool condition=false; - double threshold; - QString direction; - QString fieldName; - threshold = notification->getSpinBoxValue(); - direction = notification->getValue(); - fieldName = notification->getObjectField(); - UAVObjectField* field = object->getField(fieldName); - if (field->getName()!="") { - double value = field->getDouble(); + NotificationItem* notification = static_cast(sender()->parent()); + if (!notification) + return; + // skip duplicate notifications + // WARNING: generally we shoudn't ever trap here + // this means, that timer fires to early and notification overlap itself + if (_nowPlayingNotification == notification) { + qNotifyDebug() << "WARN: on_timerRepeated - notification was skipped!"; + notification->restartTimer(); + return; + } - switch(direction[0].toAscii()) - { - case 'E': - if(value==threshold) - condition = true; - break; - case 'G': - if(value>threshold) - condition = true; - break; - case 'L': - if(valuegetDataObject()) + .arg(notification->getObjectField()) + .arg(notification->toString()); - if(condition) - { - if(!playNotification(notification)) - { - if(!pendingNotifications.contains(notification)) - { - if(notification->timer) - if(notification->timer->isActive()) - notification->timer->stop(); -#ifdef DEBUG_NOTIFIES - qDebug() << "add to pending list - " << notification->parseNotifyMessage(); -#endif - // if audio is busy, start expiration timer - //ms = (notification->getExpiredTimeout()[in sec])*1000 - //QxtTimer::singleShot(notification->getExpireTimeout()*1000, this, SLOT(expirationTimerHandler(NotifyPluginConfiguration*)), qVariantFromValue(notification)); - pendingNotifications.append(notification); - if(!notification->expireTimer) - { - notification->expireTimer = new QTimer(notification); - connect(notification->expireTimer, SIGNAL(timeout()), this, SLOT(expireTimerHandler())); - } - notification->expireTimer->start(notification->getExpireTimeout()*1000); - } - } - } + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + UAVObject* object = objManager->getObject(notification->getDataObject()); + if (object) + checkNotificationRule(notification,object); } -bool SoundNotifyPlugin::playNotification(NotifyPluginConfiguration* notification) + +void SoundNotifyPlugin::on_expiredTimer_Notification() { - // Check: race condition, if phonon.mo got deleted don't go further - if (phonon.mo == NULL) - return false; + // fire expire timer + NotificationItem* notification = static_cast(sender()->parent()); + if(!notification) + return; + notification->stopExpireTimer(); -#ifdef DEBUG_NOTIFIES - qDebug() << "Phonon State: " << phonon.mo->state(); -#endif - if((phonon.mo->state()==Phonon::PausedState) || - (phonon.mo->state()==Phonon::StoppedState) || - phonon.firstPlay) - { - // don't fire expire timer - //notification->expire = false; - nowPlayingConfiguration = notification; - if(notification->expireTimer) - notification->expireTimer->stop(); + volatile QMutexLocker lock(&_mutex); - if(notification->getRepeatFlag()=="Repeat Once") - { - removedNotifies.append(lstNotifications.takeAt(lstNotifications.indexOf(notification))); - //if(!notification->firstStart) return true; - } - else { - if(notification->getRepeatFlag()!="Repeat Instantly") - { - QRegExp rxlen("(\\d+)"); - QString value; - int timer_value; - int pos = rxlen.indexIn(notification->getRepeatFlag()); - if (pos > -1) { - value = rxlen.cap(1); // "189" - timer_value = (value.toInt()+8)*1000; //ms*1000 + average duration of meassage - } + if (!_pendingNotifications.isEmpty()) { + qNotifyDebug() << QString("expireTimer: %1% | %2 | %3").arg(notification->getDataObject()) + .arg(notification->getObjectField()) + .arg(notification->toString()); - if(!notification->timer) - { - notification->timer = new QTimer(notification); - notification->timer->setInterval(timer_value); - connect(notification->timer, SIGNAL(timeout()), this, SLOT(repeatTimerHandler())); - } - if(!notification->timer->isActive()) - notification->timer->start(); - - //QxtTimer::singleShot(timer_value, this, SLOT(repeatTimerHandler(NotifyPluginConfiguration*)), qVariantFromValue(notification)); - } - } - notification->firstStart=false; - phonon.mo->clear(); - QString str = notification->parseNotifyMessage(); -#ifdef DEBUG_NOTIFIES - qDebug() << "play notification - " << str; -#endif - foreach(QString item, notification->getNotifyMessageList()) { - Phonon::MediaSource *ms = new Phonon::MediaSource(item); - ms->setAutoDelete(true); - phonon.mo->enqueue(*ms); - } - phonon.mo->play(); - phonon.firstPlay = false; // On Linux, you sometimes have to nudge Phonon to play 1 time before - // the state is not "Loading" anymore. - } - else - return false; // if audio is busy - - return true; -} - -//void SoundNotifyPlugin::repeatTimerHandler(NotifyPluginConfiguration* notification) -//{ -// qDebug() << "repeatTimerHandler - " << notification->parseNotifyMessage(); - -// ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); -// UAVObjectManager *objManager = pm->getObject(); -// UAVObject* object = objManager->getObject(notification->getDataObject()); -// if(object) -// checkNotificationRule(notification,object); -//} - -void SoundNotifyPlugin::repeatTimerHandler() -{ - NotifyPluginConfiguration* notification = static_cast(sender()->parent()); -#ifdef DEBUG_NOTIFIES - qDebug() << "repeatTimerHandler - " << notification->parseNotifyMessage(); -#endif - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVObject* object = objManager->getObject(notification->getDataObject()); - if(object) - checkNotificationRule(notification,object); -} - -void SoundNotifyPlugin::expireTimerHandler() -{ - // fire expire timer - NotifyPluginConfiguration* notification = static_cast(sender()->parent()); - notification->expireTimer->stop(); - - if(!pendingNotifications.isEmpty()) - { -#ifdef DEBUG_NOTIFIES - qDebug() << "expireTimerHandler - " << notification->parseNotifyMessage(); -#endif - pendingNotifications.removeOne(notification); - } + _pendingNotifications.removeOne(notification); + } } void SoundNotifyPlugin::stateChanged(Phonon::State newstate, Phonon::State oldstate) { Q_UNUSED(oldstate) -#ifdef DEBUG_NOTIFIES - qDebug() << "File length (ms): " << phonon.mo->totalTime(); - qDebug() << "New State: " << newstate; -#endif + //qNotifyDebug() << "File length (ms): " << phonon.mo->totalTime(); #ifndef Q_OS_WIN - // This is a hack to force Linux to wait until the end of the - // wav file before moving to the next in the queue. - // I wish I did not have to go through a #define, but I did not - // manage to make this work on both platforms any other way! - if (phonon.mo->totalTime()>0) - phonon.mo->setTransitionTime(phonon.mo->totalTime()); + // This is a hack to force Linux to wait until the end of the + // wav file before moving to the next in the queue. + // I wish I did not have to go through a #define, but I did not + // manage to make this work on both platforms any other way! + if (phonon.mo->totalTime()>0) + phonon.mo->setTransitionTime(phonon.mo->totalTime()); #endif - if((newstate == Phonon::PausedState) || - (newstate == Phonon::StoppedState)) - { - nowPlayingConfiguration=NULL; - if(!pendingNotifications.isEmpty()) - { - NotifyPluginConfiguration* notification = pendingNotifications.takeFirst(); -#ifdef DEBUG_NOTIFIES - qDebug() << "play audioFree - " << notification->parseNotifyMessage(); -#endif - playNotification(notification); + if ((newstate == Phonon::PausedState) || + (newstate == Phonon::StoppedState)) + { + qNotifyDebug() << "New State: " << QVariant(newstate).toString(); + + volatile QMutexLocker lock(&_mutex); + // assignment to NULL needed to detect that palying is finished + // it's useful in repeat timer handler, where we can detect + // that notification has not overlap with itself + _nowPlayingNotification = NULL; + + if (!_pendingNotifications.isEmpty()) + { + NotificationItem* notification = _pendingNotifications.takeFirst(); + qNotifyDebug_if(notification) << "play audioFree - " << notification->toString(); + playNotification(notification); + } + } else { + if (newstate == Phonon::ErrorState) { + if (phonon.mo->errorType()==0) { + qDebug() << "Phonon::ErrorState: ErrorType = " << phonon.mo->errorType(); + phonon.mo->clearQueue(); + } + } + } +} + +bool checkRange(QString fieldValue, QString enumValue, QStringList values, char direction) +{ + + bool ret = false; + switch(direction) + { + case 'E': + ret = !QString::compare(enumValue, fieldValue, Qt::CaseInsensitive) ? true : false; + break; + + default: + ret = true; + break; + }; + return ret; +} + +bool checkRange(double fieldValue, double min, double max, char direction) +{ + bool ret = false; + Q_ASSERT(min < max); + switch(direction) + { + case 'E': + ret = (fieldValue == min); + break; + + case 'G': + ret = (fieldValue > min); + break; + + case 'L': + ret = (fieldValue < min); + break; + + default: + ret = (fieldValue > min) && (fieldValue < max); + break; + }; + + return ret; +} + +void SoundNotifyPlugin::checkNotificationRule(NotificationItem* notification, UAVObject* object) +{ + bool condition=false; + + if (notification->mute()) + return; + + QString direction = notification->range(); + QString fieldName = notification->getObjectField(); + UAVObjectField* field = object->getField(fieldName); + + if (field->getName().isEmpty()) + return; + + QVariant value = field->getValue(); + if(UAVObjectField::ENUM == field->getType()) { + condition = checkRange(value.toString(), + notification->singleValue().toString(), + field->getOptions(), + direction[0].toAscii()); + } else { + condition = checkRange(value.toDouble(), + notification->singleValue().toDouble(), + notification->valueRange2(), + direction[0].toAscii()); + } + + notification->_isPlayed = condition; + // if condition has been changed, and already in false state + // we should reset _isPlayed flag and stop repeat timer + if (!notification->_isPlayed) { + notification->stopTimer(); + return; + } + + volatile QMutexLocker lock(&_mutex); + + if (!playNotification(notification)) { + if (!_pendingNotifications.contains(notification) + && (_nowPlayingNotification != notification)) { + notification->stopTimer(); + + qNotifyDebug() << "add to pending list - " << notification->toString(); + // if audio is busy, start expiration timer + //ms = (notification->getExpiredTimeout()[in sec])*1000 + //QxtTimer::singleShot(notification->getExpireTimeout()*1000, this, SLOT(expirationTimerHandler(NotificationItem*)), qVariantFromValue(notification)); + _pendingNotifications.append(notification); + notification->startExpireTimer(); + connect(notification->getExpireTimer(), SIGNAL(timeout()), + this, SLOT(on_expiredTimer_Notification()), Qt::UniqueConnection); + } + } +} + +bool SoundNotifyPlugin::playNotification(NotificationItem* notification) +{ + if(!notification) + return false; + + // Check: race condition, if phonon.mo got deleted don't go further + if (phonon.mo == NULL) + return false; + + //qNotifyDebug() << "Phonon State: " << phonon.mo->state(); + + if ((phonon.mo->state()==Phonon::PausedState) + || (phonon.mo->state()==Phonon::StoppedState) + || phonon.firstPlay) + { + _nowPlayingNotification = notification; + notification->stopExpireTimer(); + + if (notification->retryString() == "Repeat Once") { + _toRemoveNotifications.append(_notificationList.takeAt(_notificationList.indexOf(notification))); + } else { + if (notification->retryString() != "Repeat Instantly") { + QRegExp rxlen("(\\d+)"); + QString value; + int timer_value; + int pos = rxlen.indexIn(notification->retryString()); + if (pos > -1) { + value = rxlen.cap(1); // "189" + + // needs to correct repeat timer value, + // acording to message play duration, + // we don't measure duration of each message, + // simply take average duration + enum { eAverageDurationSec = 8 }; + + enum { eSecToMsec = 1000 }; + + timer_value = (value.toInt() + eAverageDurationSec) * eSecToMsec; } - } else if (newstate == Phonon::ErrorState) - { - if(phonon.mo->errorType()==0) { - qDebug() << "Phonon::ErrorState: ErrorType = " << phonon.mo->errorType(); - phonon.mo->clearQueue(); - } - } -// if(newstate == Phonon::BufferingState) -// qDebug() << "Phonon::BufferingState!!!"; + + notification->startTimer(timer_value); + connect(notification->getTimer(), SIGNAL(timeout()), + this, SLOT(on_timerRepeated_Notification()), Qt::UniqueConnection); + } + } + phonon.mo->clear(); + qNotifyDebug() << "play: " << notification->toString(); + foreach (QString item, notification->toSoundList()) { + Phonon::MediaSource *ms = new Phonon::MediaSource(item); + ms->setAutoDelete(true); + phonon.mo->enqueue(*ms); + } + phonon.mo->play(); + phonon.firstPlay = false; // On Linux, you sometimes have to nudge Phonon to play 1 time before + // the state is not "Loading" anymore. + return true; + + } + + return false; } Q_EXPORT_PLUGIN(SoundNotifyPlugin) diff --git a/ground/openpilotgcs/src/plugins/notify/notifyplugin.h b/ground/openpilotgcs/src/plugins/notify/notifyplugin.h index 0d0eb50d8..6a142ff03 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifyplugin.h +++ b/ground/openpilotgcs/src/plugins/notify/notifyplugin.h @@ -32,7 +32,7 @@ #include "uavtalk/telemetrymanager.h" #include "uavobjectmanager.h" #include "uavobject.h" -#include "notifypluginconfiguration.h" +#include "notificationitem.h" #include #include @@ -44,71 +44,69 @@ class NotifyPluginOptionsPage; typedef struct { Phonon::MediaObject* mo; - NotifyPluginConfiguration* notify; - bool firstPlay; + NotificationItem* notify; + bool firstPlay; } PhononObject, *pPhononObject; + class SoundNotifyPlugin : public Core::IConfigurablePlugin -{ - Q_OBJECT -public: - SoundNotifyPlugin(); - ~SoundNotifyPlugin(); +{ + Q_OBJECT +public: + SoundNotifyPlugin(); + ~SoundNotifyPlugin(); - void extensionsInitialized(); - bool initialize(const QStringList & arguments, QString * errorString); - void readConfig( QSettings* qSettings, Core::UAVConfigInfo *configInfo); - void saveConfig( QSettings* qSettings, Core::UAVConfigInfo *configInfo); - void shutdown(); + void extensionsInitialized(); + bool initialize(const QStringList & arguments, QString * errorString); + void readConfig( QSettings* qSettings, Core::UAVConfigInfo *configInfo); + void saveConfig( QSettings* qSettings, Core::UAVConfigInfo *configInfo); + void shutdown(); - QList getListNotifications() { return lstNotifications; } - //void setListNotifications(QList& list_notify) { } - NotifyPluginConfiguration* getCurrentNotification(){ return ¤tNotification;} - - bool getEnableSound() const { return enableSound; } - void setEnableSound(bool value) {enableSound = value; } - + QList getListNotifications() { return _notificationList; } + NotificationItem* getCurrentNotification(){ return ¤tNotification;} + bool getEnableSound() const { return enableSound; } + void setEnableSound(bool value) {enableSound = value; } private: - bool configured; // just for migration,delete later - bool enableSound; - QList< QList* > lstMediaSource; - QStringList mediaSource; - //QMap mapMediaObjects; - QMultiMap mapMediaObjects; + Q_DISABLE_COPY(SoundNotifyPlugin) - QSettings* settings; - - QList lstNotifiedUAVObjects; - - QList lstNotifications; - QList pendingNotifications; - QList removedNotifies; - - NotifyPluginConfiguration currentNotification; - NotifyPluginConfiguration* nowPlayingConfiguration; - - QString m_field; - PhononObject phonon; - NotifyPluginOptionsPage *mop; - TelemetryManager* telMngr; - - bool playNotification(NotifyPluginConfiguration* notification); - void checkNotificationRule(NotifyPluginConfiguration* notification, UAVObject* object); - void readConfig_0_0_0(); + bool playNotification(NotificationItem* notification); + void checkNotificationRule(NotificationItem* notification, UAVObject* object); + void readConfig_0_0_0(); private slots: - void onTelemetryManagerAdded(QObject* obj); - void onAutopilotDisconnect(); - void connectNotifications(); - void updateNotificationList(QList list); - void resetNotification(void); - void appendNotification(UAVObject *object); - void repeatTimerHandler(void); - void expireTimerHandler(void); - void stateChanged(Phonon::State newstate, Phonon::State oldstate); + + void onTelemetryManagerAdded(QObject* obj); + void onAutopilotDisconnect(); + void connectNotifications(); + void updateNotificationList(QList list); + void resetNotification(void); + void on_arrived_Notification(UAVObject *object); + void on_timerRepeated_Notification(void); + void on_expiredTimer_Notification(void); + void stateChanged(Phonon::State newstate, Phonon::State oldstate); + +private: + bool enableSound; + QList< QList* > lstMediaSource; + QStringList mediaSource; + QMultiMap mapMediaObjects; + QSettings* settings; + + QList lstNotifiedUAVObjects; + QList _notificationList; + QList _pendingNotifications; + QList _toRemoveNotifications; + + NotificationItem currentNotification; + NotificationItem* _nowPlayingNotification; + + PhononObject phonon; + NotifyPluginOptionsPage* mop; + TelemetryManager* telMngr; + QMutex _mutex; }; #endif // SOUNDNOTIFYPLUGIN_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.cpp b/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.cpp deleted file mode 100644 index 94b88421e..000000000 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/** - ****************************************************************************** - * - * @file notifyPluginConfiguration.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Notify Plugin configuration - * @see The GNU Public License (GPL) Version 3 - * @defgroup notifyplugin - * @{ - * - *****************************************************************************/ -/* - * 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 3 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; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "notifypluginconfiguration.h" -#include -#include -#include "utils/pathutils.h" - - -NotifyPluginConfiguration::NotifyPluginConfiguration(QObject *parent) : - QObject(parent), - isNowPlaying(0), - firstStart(1), - soundCollectionPath(""), - currentLanguage("default"), - dataObject(""), - objectField(""), - value("Equal to"), - sound1(""), - sound2(""), - sound3(""), - sayOrder("Never"), - spinBoxValue(0), - repeatString("Repeat Instantly"), - repeatTimeout(true), - expireTimeout(15) - -{ - timer = NULL; - expireTimer = NULL; -} - -void NotifyPluginConfiguration::copyTo(NotifyPluginConfiguration* that) const -{ - - that->isNowPlaying = isNowPlaying; - that->firstStart = firstStart; - that->soundCollectionPath = soundCollectionPath; - that->currentLanguage = currentLanguage; - that->soundCollectionPath = soundCollectionPath; - that->dataObject = dataObject; - that->objectField = objectField; - that->value = value; - that->sound1 = sound1; - that->sound2 = sound2; - that->sound3 = sound3; - that->sayOrder = sayOrder; - that->spinBoxValue = spinBoxValue; - that->repeatString = repeatString; - that->repeatTimeout = repeatTimeout; - that->expireTimeout = expireTimeout; -} - - -void NotifyPluginConfiguration::saveState(QSettings* settings) const -{ - settings->setValue("SoundCollectionPath", Utils::PathUtils().RemoveDataPath(getSoundCollectionPath())); - settings->setValue(QLatin1String("CurrentLanguage"), getCurrentLanguage()); - settings->setValue(QLatin1String("ObjectField"), getObjectField()); - settings->setValue(QLatin1String("DataObject"), getDataObject()); - settings->setValue(QLatin1String("Value"), getValue()); - settings->setValue(QLatin1String("ValueSpinBox"), getSpinBoxValue()); - settings->setValue(QLatin1String("Sound1"), getSound1()); - settings->setValue(QLatin1String("Sound2"), getSound2()); - settings->setValue(QLatin1String("Sound3"), getSound3()); - settings->setValue(QLatin1String("SayOrder"), getSayOrder()); - settings->setValue(QLatin1String("Repeat"), getRepeatFlag()); - settings->setValue(QLatin1String("ExpireTimeout"), getExpireTimeout()); -} - -void NotifyPluginConfiguration::restoreState(QSettings* settings) -{ - //settings = Core::ICore::instance()->settings(); - setSoundCollectionPath(Utils::PathUtils().InsertDataPath(settings->value(QLatin1String("SoundCollectionPath"), tr("")).toString())); - setCurrentLanguage(settings->value(QLatin1String("CurrentLanguage"), tr("")).toString()); - setDataObject(settings->value(QLatin1String("DataObject"), tr("")).toString()); - setObjectField(settings->value(QLatin1String("ObjectField"), tr("")).toString()); - setValue(settings->value(QLatin1String("Value"), tr("")).toString()); - setSound1(settings->value(QLatin1String("Sound1"), tr("")).toString()); - setSound2(settings->value(QLatin1String("Sound2"), tr("")).toString()); - setSound3(settings->value(QLatin1String("Sound3"), tr("")).toString()); - setSayOrder(settings->value(QLatin1String("SayOrder"), tr("")).toString()); - setSpinBoxValue(settings->value(QLatin1String("ValueSpinBox"), tr("")).toDouble()); - setRepeatFlag(settings->value(QLatin1String("Repeat"), tr("")).toString()); - setExpireTimeout(settings->value(QLatin1String("ExpireTimeout"), tr("")).toInt()); -} - - -QString NotifyPluginConfiguration::parseNotifyMessage() -{ - // tips: - // check of *.wav files exist needed for playing phonon queues; - // if phonon player don't find next file in queue, it buzz - - QString str,str1; - str1= getSayOrder(); - str = QString("%L1 ").arg(getSpinBoxValue()); - int position = 0xFF; - // generate queue of sound files to play - notifyMessageList.clear(); - - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath() + "/" + getCurrentLanguage()+"/"+getSound1()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath() + "/" + getCurrentLanguage()+"/"+getSound1()+".wav")); - else - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath() + "/default/"+getSound1()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath() + "/default/"+getSound1()+".wav")); - - if(getSound2()!="") - { - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath() + "/" + getCurrentLanguage()+"/"+getSound2()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath() + "/" + getCurrentLanguage()+"/"+getSound2()+".wav")); - else - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath() + "/default/"+getSound2()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath() + "/default/"+getSound2()+".wav")); - } - - if(getSound3()!="") - { - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath()+ "/" + getCurrentLanguage()+"/"+getSound3()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath()+ "/" + getCurrentLanguage()+"/"+getSound3()+".wav")); - else - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath()+"/default/"+getSound3()+".wav"))) - notifyMessageList.append(QDir::toNativeSeparators(getSoundCollectionPath()+"/default/"+getSound3()+".wav")); - } - - switch(str1.at(0).toAscii()) - { - case 'N'://NEVER: - str = getSound1()+" "+getSound2()+" "+getSound3(); - position = 0xFF; - break; - - case 'B'://BEFORE: - str = QString("%L1 ").arg(getSpinBoxValue())+getSound1()+" "+getSound2()+" "+getSound3(); - position = 0; - break; - - case 'A'://AFTER: - switch(str1.at(6).toAscii()) - { - case 'f': - str = getSound1()+QString(" %L1 ").arg(getSpinBoxValue())+getSound2()+" "+getSound3(); - position = 1; - break; - case 's': - str = getSound1()+" "+getSound2()+QString(" %L1").arg(getSpinBoxValue())+" "+getSound3(); - position = 2; - break; - case 't': - str = getSound1()+" "+getSound2()+" "+getSound3()+QString(" %L1").arg(getSpinBoxValue()); - position = 3; - break; - } - break; - } - - if(position!=0xFF) - { - QStringList numberParts = QString("%1").arg(getSpinBoxValue()).trimmed().split("."); - QStringList numberFiles; - - if((numberParts.at(0).size()==1) || (numberParts.at(0).toInt()<20)) - { - //if(numberParts.at(0)!="0") - numberFiles.append(numberParts.at(0)); - } else { - int i=0; - if(numberParts.at(0).right(2).toInt()<20 && numberParts.at(0).right(2).toInt()!=0) { - if(numberParts.at(0).right(2).toInt()<10) - numberFiles.append(numberParts.at(0).right(1)); - else - numberFiles.append(numberParts.at(0).right(2)); - i=2; - } - for(;i1) { - numberFiles.append("point"); - if((numberParts.at(1).size()==1) /*|| (numberParts.at(1).toInt()<20)*/) - numberFiles.append(numberParts.at(1)); - else { - if(numberParts.at(1).left(1)=="0") - numberFiles.append(numberParts.at(1).left(1)); - else - numberFiles.append(numberParts.at(1).left(1)+'0'); - numberFiles.append(numberParts.at(1).right(1)); - } - } - foreach(QString fileName,numberFiles) { - fileName+=".wav"; - QString filePath = QDir::toNativeSeparators(getSoundCollectionPath()+"/"+ getCurrentLanguage()+"/"+fileName); - if(QFile::exists(filePath)) - notifyMessageList.insert(position++,QDir::toNativeSeparators(getSoundCollectionPath()+ "/"+getCurrentLanguage()+"/"+fileName)); - else { - if(QFile::exists(QDir::toNativeSeparators(getSoundCollectionPath()+"/default/"+fileName))) - notifyMessageList.insert(position++,QDir::toNativeSeparators(getSoundCollectionPath()+"/default/"+fileName)); - else { - notifyMessageList.clear(); - break; // if no some of *.wav files, then don't play number! - } - } - } - } - - //str.replace(QString(".wav | .mp3"), QString("")); - return str; -} diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.h b/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.h deleted file mode 100644 index ad13a82a0..000000000 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginconfiguration.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - ****************************************************************************** - * - * @file notifypluginconfiguration.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief Notify Plugin configuration header - * @see The GNU Public License (GPL) Version 3 - * @defgroup notifyplugin - * @{ - * - *****************************************************************************/ -/* - * 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 3 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; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef NOTIFYPLUGINCONFIGURATION_H -#define NOTIFYPLUGINCONFIGURATION_H -#include -#include "qsettings.h" -#include -#include - -using namespace Core; - -class NotifyPluginConfiguration : public QObject -{ - Q_OBJECT -public: - explicit NotifyPluginConfiguration(QObject *parent = 0); - - QTimer* timer; - QTimer* expireTimer; - bool isNowPlaying; // - bool firstStart; - - void copyTo(NotifyPluginConfiguration*) const; - - QString getSound1() const { return sound1; } - void setSound1(QString text) {sound1 = text; } - - QString getSound2() const { return sound2; } - void setSound2(QString text) {sound2 = text; } - - QString getSound3() const { return sound3; } - void setSound3(QString text) {sound3 = text; } - - QString getValue() const { return value; } - void setValue(QString text) {value = text; } - - QString getSayOrder() const { return sayOrder; } - void setSayOrder(QString text) {sayOrder = text; } - - double getSpinBoxValue() const { return spinBoxValue; } - void setSpinBoxValue(double value) {spinBoxValue = value; } - - - QString getDataObject() const { return dataObject; } - void setDataObject(QString text) {dataObject = text; } - - QString getObjectField() const { return objectField; } - void setObjectField(QString text) { objectField = text; } - - QString getSoundCollectionPath() const { return soundCollectionPath; } - void setSoundCollectionPath(QString text) { soundCollectionPath = text; } - - QString getCurrentLanguage() const { return currentLanguage; } - void setCurrentLanguage(QString text) { currentLanguage = text; } - - QStringList getNotifyMessageList() const { return notifyMessageList; } - void setNotifyMessageList(QStringList text) { notifyMessageList = text; } - - QString getRepeatFlag() const { return repeatString; } - void setRepeatFlag(QString value) { repeatString = value; } - - bool getRepeatTimeout() const { return repeatTimeout; } - void setRepeatTimeout(bool value) { repeatTimeout = value; } - - int getExpireTimeout() const { return expireTimeout; } - void setExpireTimeout(int value) { expireTimeout = value; } - - - - void saveState(QSettings* settings) const; - void restoreState(QSettings* settings); - QString parseNotifyMessage(); - -private: - QStringList notifyMessageList; - QString soundCollectionPath; - QString currentLanguage; - QString dataObject; - QString objectField; - - QString value; - QString sound1; - QString sound2; - QString sound3; - QString sayOrder; - double spinBoxValue; - QString repeatString; - bool repeatTimeout; - int repeatTimerValue; - int expireTimeout; - -}; - -Q_DECLARE_METATYPE(NotifyPluginConfiguration*) - -#endif // NOTIFYPLUGINCONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp index 5dee5678a..49b274e38 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp @@ -27,7 +27,7 @@ #include "notifypluginoptionspage.h" #include -#include "notifypluginconfiguration.h" +#include "notificationitem.h" #include "ui_notifypluginoptionspage.h" #include "extensionsystem/pluginmanager.h" #include "utils/pathutils.h" @@ -39,438 +39,601 @@ #include #include #include +#include +#include #include "notifyplugin.h" #include "notifyitemdelegate.h" #include "notifytablemodel.h" +#include "notifylogging.h" -NotifyPluginOptionsPage::NotifyPluginOptionsPage(/*NotifyPluginConfiguration *config,*/ QObject *parent) : - IOptionsPage(parent), - owner((SoundNotifyPlugin*)parent), - currentCollectionPath(""), - privListNotifications(((SoundNotifyPlugin*)parent)->getListNotifications()) -{ - -} +static const char* cStrEqualTo = "Equal to"; +static const char* cStrLargeThan = "Large than"; +static const char* cStrLowerThan = "Lower than"; +static const char* cStrInRange = "In range"; -//creates options page widget (uses the UI file) +NotifyPluginOptionsPage::NotifyPluginOptionsPage(QObject *parent) + : IOptionsPage(parent) + , _objManager(*ExtensionSystem::PluginManager::instance()->getObject()) + , _owner(qobject_cast(parent)) + , _dynamicFieldLimit(NULL) + , _dynamicFieldWidget(NULL) + , _dynamicFieldType(-1) + , _sayOrder(NULL) + , _form(NULL) + , _selectedNotification(NULL) +{} + +NotifyPluginOptionsPage::~NotifyPluginOptionsPage() +{} + QWidget *NotifyPluginOptionsPage::createPage(QWidget *parent) { + _optionsPage.reset(new Ui::NotifyPluginOptionsPage()); + //main widget + QWidget* optionsPageWidget = new QWidget; + _dynamicFieldWidget = NULL; + _dynamicFieldLimit = NULL; + resetFieldType(); + //save ref to form, needed for binding dynamic fields in future + _form = optionsPageWidget; + //main layout + _optionsPage->setupUi(optionsPageWidget); - options_page = new Ui::NotifyPluginOptionsPage(); - //main widget - QWidget *optionsPageWidget = new QWidget; - //main layout - options_page->setupUi(optionsPageWidget); + _optionsPage->SoundDirectoryPathChooser->setExpectedKind(Utils::PathChooser::Directory); + _optionsPage->SoundDirectoryPathChooser->setPromptDialogTitle(tr("Choose sound collection directory")); - delegateItems.clear(); - listSoundFiles.clear(); + connect(_optionsPage->SoundDirectoryPathChooser, SIGNAL(changed(const QString&)), + this, SLOT(on_clicked_buttonSoundFolder(const QString&))); + connect(_optionsPage->SoundCollectionList, SIGNAL(currentIndexChanged (int)), + this, SLOT(on_changedIndex_soundLanguage(int))); - delegateItems << "Repeat Once" - << "Repeat Instantly" - << "Repeat 10 seconds" - << "Repeat 30 seconds" - << "Repeat 1 minute"; + connect(this, SIGNAL(updateNotifications(QList)), + _owner, SLOT(updateNotificationList(QList))); + //connect(this, SIGNAL(resetNotification()),owner, SLOT(resetNotification())); - options_page->chkEnableSound->setChecked(owner->getEnableSound()); - options_page->SoundDirectoryPathChooser->setExpectedKind(Utils::PathChooser::Directory); - options_page->SoundDirectoryPathChooser->setPromptDialogTitle(tr("Choose sound collection directory")); + _privListNotifications = _owner->getListNotifications(); + // [1] + setSelectedNotification(_owner->getCurrentNotification()); + addDynamicFieldLayout(); + // [2] + updateConfigView(_selectedNotification); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - objManager = pm->getObject(); + initRulesTable(); + initButtons(); + initPhononPlayer(); - // Fills the combo boxes for the UAVObjects - QList< QList > objList = objManager->getDataObjects(); - foreach (QList list, objList) { - foreach (UAVDataObject* obj, list) { - options_page->UAVObject->addItem(obj->getName()); - } - } + int curr_row = _privListNotifications.indexOf(_selectedNotification); + _notifyRulesSelection->setCurrentIndex(_notifyRulesModel->index(curr_row, 0, QModelIndex()), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); - connect(options_page->SoundDirectoryPathChooser, SIGNAL(changed(const QString&)), this, SLOT(on_buttonSoundFolder_clicked(const QString&))); - connect(options_page->SoundCollectionList, SIGNAL(currentIndexChanged (int)), this, SLOT(on_soundLanguage_indexChanged(int))); - connect(options_page->buttonAdd, SIGNAL(pressed()), this, SLOT(on_buttonAddNotification_clicked())); - connect(options_page->buttonDelete, SIGNAL(pressed()), this, SLOT(on_buttonDeleteNotification_clicked())); - connect(options_page->buttonModify, SIGNAL(pressed()), this, SLOT(on_buttonModifyNotification_clicked())); -// connect(options_page->buttonTestSound1, SIGNAL(clicked()), this, SLOT(on_buttonTestSound1_clicked())); -// connect(options_page->buttonTestSound2, SIGNAL(clicked()), this, SLOT(on_buttonTestSound2_clicked())); - connect(options_page->buttonPlayNotification, SIGNAL(clicked()), this, SLOT(on_buttonTestSoundNotification_clicked())); - connect(options_page->chkEnableSound, SIGNAL(toggled(bool)), this, SLOT(on_chkEnableSound_toggled(bool))); - - - connect(options_page->UAVObject, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_UAVObject_indexChanged(QString))); - connect(this, SIGNAL(updateNotifications(QList)), - owner, SLOT(updateNotificationList(QList))); - connect(this, SIGNAL(resetNotification()),owner, SLOT(resetNotification())); - - //emit resetNotification(); - - - privListNotifications.clear(); - - for (int i = 0; i < owner->getListNotifications().size(); ++i) { - NotifyPluginConfiguration* notification = new NotifyPluginConfiguration(); - owner->getListNotifications().at(i)->copyTo(notification); - privListNotifications.append(notification); - } - - updateConfigView(owner->getCurrentNotification()); - - options_page->chkEnableSound->setChecked(owner->getEnableSound()); - - QStringList headerStrings; - headerStrings << "Name" << "Repeats" << "Lifetime,sec"; - - notifyRulesModel = new NotifyTableModel(&privListNotifications,headerStrings); - options_page->notifyRulesView->setModel(notifyRulesModel); - options_page->notifyRulesView->resizeRowsToContents(); - notifyRulesSelection = new QItemSelectionModel(notifyRulesModel); - connect(notifyRulesSelection, SIGNAL(selectionChanged ( const QItemSelection &, const QItemSelection & )), - this, SLOT(on_tableNotification_changeSelection( const QItemSelection & , const QItemSelection & ))); - connect(this, SIGNAL(entryUpdated(int)), - notifyRulesModel, SLOT(entryUpdated(int))); - connect(this, SIGNAL(entryAdded(int)), - notifyRulesModel, SLOT(entryAdded(int))); - - options_page->notifyRulesView->setSelectionModel(notifyRulesSelection); - options_page->notifyRulesView->setItemDelegate(new NotifyItemDelegate(delegateItems,this)); - - options_page->notifyRulesView->setColumnWidth(0,200); - options_page->notifyRulesView->setColumnWidth(1,150); - options_page->notifyRulesView->setColumnWidth(2,100); - - options_page->buttonModify->setEnabled(false); - options_page->buttonDelete->setEnabled(false); - options_page->buttonPlayNotification->setEnabled(false); - -// sound1 = Phonon::createPlayer(Phonon::NotificationCategory); -// sound2 = Phonon::createPlayer(Phonon::NotificationCategory); - notifySound = Phonon::createPlayer(Phonon::NotificationCategory); -// audioOutput = new Phonon::AudioOutput(Phonon::NotificationCategory, this); -// Phonon::createPath(sound1, audioOutput); -// Phonon::createPath(sound2, audioOutput); -// Phonon::createPath(notifySound, audioOutput); - -// connect(sound1,SIGNAL(stateChanged(Phonon::State,Phonon::State)),SLOT(changeButtonText(Phonon::State,Phonon::State))); -// connect(sound2,SIGNAL(stateChanged(Phonon::State,Phonon::State)),SLOT(changeButtonText(Phonon::State,Phonon::State))); - connect(notifySound,SIGNAL(stateChanged(Phonon::State,Phonon::State)), - this,SLOT(changeButtonText(Phonon::State,Phonon::State))); - - return optionsPageWidget; + return optionsPageWidget; } -void NotifyPluginOptionsPage::showPersistentComboBox( const QModelIndex & parent, int start, int end ) -{ -// for (int i=start; itableNotifications->openPersistentEditor(options_page->tableNotifications->item(i,1)); -// } -} - -void NotifyPluginOptionsPage::showPersistentComboBox2( const QModelIndex & topLeft, const QModelIndex & bottomRight ) -{ - //for (QModelIndex i=topLeft; itableNotifications->openPersistentEditor(options_page->tableNotifications->item(options_page->tableNotifications->currentRow(),1)); - } -} - - -void NotifyPluginOptionsPage::getOptionsPageValues(NotifyPluginConfiguration* notification) -{ - notification->setSoundCollectionPath(options_page->SoundDirectoryPathChooser->path()); - notification->setCurrentLanguage(options_page->SoundCollectionList->currentText()); - notification->setDataObject(options_page->UAVObject->currentText()); - notification->setObjectField(options_page->UAVObjectField->currentText()); - notification->setSound1(options_page->Sound1->currentText()); - notification->setSound2(options_page->Sound2->currentText()); - notification->setSound3(options_page->Sound3->currentText()); - notification->setSayOrder(options_page->SayOrder->currentText()); - notification->setValue(options_page->Value->currentText()); - notification->setSpinBoxValue(options_page->ValueSpinBox->value()); - -// if(notifyRulesSelection->currentIndex().row()>-1) -// { -// //qDebug() << "delegate value:" << options_page->tableNotifications->item(options_page->tableNotifications->currentRow(),1)->data(Qt::EditRole); -// notification->setRepeatFlag(notifyRulesModel->data(notifyRulesSelection->currentIndex(),Qt::DisplayRole).toString()); -// } -} - -//////////////////////////////////////////// -// Called when the user presses apply or OK. -// -// Saves the current values -// -//////////////////////////////////////////// void NotifyPluginOptionsPage::apply() { - - getOptionsPageValues(owner->getCurrentNotification()); - - owner->setEnableSound(options_page->chkEnableSound->isChecked()); - //owner->setListNotifications(privListNotifications); - emit updateNotifications(privListNotifications); + getOptionsPageValues(_owner->getCurrentNotification()); + _owner->setEnableSound(_optionsPage->chkEnableSound->isChecked()); + emit updateNotifications(_privListNotifications); } void NotifyPluginOptionsPage::finish() { - disconnect(notifySound,SIGNAL(stateChanged(Phonon::State,Phonon::State)), - this,SLOT(changeButtonText(Phonon::State,Phonon::State))); - if(notifySound) - { - notifySound->stop(); - notifySound->clear(); - } + disconnect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_UAVField(QString))); - delete options_page; -} - - - -////////////////////////////////////////////////////////////////////////////// -// Fills in the combo box when value is changed in the -// combo box -////////////////////////////////////////////////////////////////////////////// -void NotifyPluginOptionsPage::on_UAVObject_indexChanged(QString val) { - options_page->UAVObjectField->clear(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast( objManager->getObject(val) ); - QList fieldList = obj->getFields(); - foreach (UAVObjectField* field, fieldList) { - options_page->UAVObjectField->addItem(field->getName()); + disconnect(_testSound.data(),SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this,SLOT(on_changed_playButtonText(Phonon::State,Phonon::State))); + if (_testSound) { + _testSound->stop(); + _testSound->clear(); } } -// locate collection folder on disk -void NotifyPluginOptionsPage::on_buttonSoundFolder_clicked(const QString& path) +void NotifyPluginOptionsPage::initButtons() { - QDir dirPath(path); - listDirCollections = dirPath.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); - options_page->SoundCollectionList->clear(); - options_page->SoundCollectionList->addItems(listDirCollections); + _optionsPage->chkEnableSound->setChecked(_owner->getEnableSound()); + connect(_optionsPage->chkEnableSound, SIGNAL(toggled(bool)), + this, SLOT(on_toggled_checkEnableSound(bool))); + + _optionsPage->buttonModify->setEnabled(false); + _optionsPage->buttonDelete->setEnabled(false); + _optionsPage->buttonPlayNotification->setEnabled(false); + connect(_optionsPage->buttonAdd, SIGNAL(pressed()), + this, SLOT(on_clicked_buttonAddNotification())); + connect(_optionsPage->buttonDelete, SIGNAL(pressed()), + this, SLOT(on_clicked_buttonDeleteNotification())); + connect(_optionsPage->buttonModify, SIGNAL(pressed()), + this, SLOT(on_clicked_buttonModifyNotification())); + connect(_optionsPage->buttonPlayNotification, SIGNAL(clicked()), + this, SLOT(on_clicked_buttonTestSoundNotification())); } - -void NotifyPluginOptionsPage::on_soundLanguage_indexChanged(int index) +void NotifyPluginOptionsPage::initPhononPlayer() { - options_page->SoundCollectionList->setCurrentIndex(index); + _testSound.reset(Phonon::createPlayer(Phonon::NotificationCategory)); + connect(_testSound.data(),SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this,SLOT(on_changed_playButtonText(Phonon::State,Phonon::State))); + connect(_testSound.data(), SIGNAL(finished(void)), this, SLOT(on_FinishedPlaying(void))); +} - currentCollectionPath = options_page->SoundDirectoryPathChooser->path() + - QDir::toNativeSeparators("/" + options_page->SoundCollectionList->currentText()); +void NotifyPluginOptionsPage::initRulesTable() +{ + qNotifyDebug_if(_notifyRulesModel.isNull()) << "_notifyRulesModel.isNull())"; + qNotifyDebug_if(!_notifyRulesSelection) << "_notifyRulesSelection.isNull())"; + _notifyRulesModel.reset(new NotifyTableModel(_privListNotifications)); + _notifyRulesSelection = new QItemSelectionModel(_notifyRulesModel.data()); - QDir dirPath(currentCollectionPath); - QStringList filters; - filters << "*.mp3" << "*.wav"; - dirPath.setNameFilters(filters); - listSoundFiles = dirPath.entryList(filters); - listSoundFiles.replaceInStrings(QRegExp(".mp3|.wav"), ""); - options_page->Sound1->clear(); - options_page->Sound2->clear(); - options_page->Sound3->clear(); - options_page->Sound1->addItems(listSoundFiles); - options_page->Sound2->addItem(""); - options_page->Sound2->addItems(listSoundFiles); - options_page->Sound3->addItem(""); - options_page->Sound3->addItems(listSoundFiles); + connect(_notifyRulesSelection, SIGNAL(selectionChanged ( const QItemSelection &, const QItemSelection & )), + this, SLOT(on_changedSelection_notifyTable( const QItemSelection & , const QItemSelection & ))); + connect(this, SIGNAL(entryUpdated(int)), + _notifyRulesModel.data(), SLOT(entryUpdated(int))); + + _optionsPage->notifyRulesView->setModel(_notifyRulesModel.data()); + _optionsPage->notifyRulesView->setSelectionModel(_notifyRulesSelection); + _optionsPage->notifyRulesView->setItemDelegate(new NotifyItemDelegate(this)); + + _optionsPage->notifyRulesView->resizeRowsToContents(); + _optionsPage->notifyRulesView->setColumnWidth(eMessageName,200); + _optionsPage->notifyRulesView->setColumnWidth(eRepeatValue,120); + _optionsPage->notifyRulesView->setColumnWidth(eExpireTimer,100); + _optionsPage->notifyRulesView->setColumnWidth(eTurnOn,60); + _optionsPage->notifyRulesView->setDragEnabled(true); + _optionsPage->notifyRulesView->setAcceptDrops(true); + _optionsPage->notifyRulesView->setDropIndicatorShown(true); + _optionsPage->notifyRulesView->setDragDropMode(QAbstractItemView::InternalMove); +} + +UAVObjectField* NotifyPluginOptionsPage::getObjectFieldFromSelected() +{ + return (_currUAVObject) ? _currUAVObject->getField(_selectedNotification->getObjectField()) : NULL; +} + +void NotifyPluginOptionsPage::setSelectedNotification(NotificationItem* ntf) +{ + _selectedNotification = ntf; + _currUAVObject = dynamic_cast(_objManager.getObject(_selectedNotification->getDataObject())); + if(!_currUAVObject) { + qNotifyDebug() << "no such UAVObject: " << _selectedNotification->getDataObject(); + } +} + +void NotifyPluginOptionsPage::addDynamicFieldLayout() +{ + // there is no need to check (objField == NULL), + // thus it doesn't use in this field directly + + QSizePolicy labelSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + labelSizePolicy.setHorizontalStretch(0); + labelSizePolicy.setVerticalStretch(0); +// labelSizePolicy.setHeightForWidth(UAVObject->sizePolicy().hasHeightForWidth()); + + + QLabel* labelSayOrder = new QLabel("Say order ", _form); + labelSayOrder->setSizePolicy(labelSizePolicy); + + _optionsPage->dynamicValueLayout->addWidget(labelSayOrder); + _sayOrder = new QComboBox(_form); + _optionsPage->dynamicValueLayout->addWidget(_sayOrder); + _sayOrder->addItems(NotificationItem::sayOrderValues); + + QLabel* labelValueIs = new QLabel("Value is ", _form); + labelValueIs->setSizePolicy(labelSizePolicy); + _optionsPage->dynamicValueLayout->addWidget(labelValueIs); + + _dynamicFieldLimit = new QComboBox(_form); + _optionsPage->dynamicValueLayout->addWidget(_dynamicFieldLimit); + UAVObjectField* field = getObjectFieldFromSelected(); + addDynamicField(field); +} + +void NotifyPluginOptionsPage::addDynamicField(UAVObjectField* objField) +{ + if(!objField) { + qNotifyDebug() << "addDynamicField | input objField == NULL"; + return; + } + if (objField->getType() == _dynamicFieldType) { + if (QComboBox* fieldValue = dynamic_cast(_dynamicFieldWidget)) { + fieldValue->clear(); + QStringList enumValues(objField->getOptions()); + fieldValue->addItems(enumValues); + } + return; + } + + disconnect(_dynamicFieldLimit, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_rangeValue(QString))); + + _dynamicFieldLimit->clear(); + QStringList rangeValues; + if (UAVObjectField::ENUM == objField->getType()) { + rangeValues << cStrEqualTo << cStrInRange; + _dynamicFieldLimit->addItems(rangeValues); + _dynamicFieldLimit->setCurrentIndex(rangeValues.indexOf(_selectedNotification->range())); + + } else { + rangeValues << cStrEqualTo << cStrLargeThan << cStrLowerThan << cStrInRange; + _dynamicFieldLimit->addItems(rangeValues); + connect(_dynamicFieldLimit, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_rangeValue(QString))); + } + + addDynamicFieldWidget(objField); +} + +void NotifyPluginOptionsPage::addDynamicFieldWidget(UAVObjectField* objField) +{ + if(!objField) { + qNotifyDebug() << "objField == NULL!"; + return; + } + // check if dynamic fileld already settled, + // so if its exists remove it and install new field + if (_dynamicFieldWidget) { + _optionsPage->dynamicValueLayout->removeWidget(_dynamicFieldWidget); + delete _dynamicFieldWidget; + _dynamicFieldWidget = NULL; + } + + QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + + _dynamicFieldType = objField->getType(); + switch(_dynamicFieldType) + { + case UAVObjectField::ENUM: + { + _dynamicFieldWidget = new QComboBox(_form); + QStringList enumValues(objField->getOptions()); + (dynamic_cast(_dynamicFieldWidget))->addItems(enumValues); + } + break; + + default: + Q_ASSERT(_dynamicFieldLimit); + if (_dynamicFieldLimit->currentText() == cStrInRange) { + _dynamicFieldWidget = new QLineEdit(_form); + + (static_cast(_dynamicFieldWidget))->setInputMask("999.99 - 999.99;"); + (static_cast(_dynamicFieldWidget))->setText("0000000000"); + (static_cast(_dynamicFieldWidget))->setCursorPosition(0); + } else { + _dynamicFieldWidget = new QDoubleSpinBox(_form); + (dynamic_cast(_dynamicFieldWidget))->setRange(000.00, 999.99); + } + break; + }; + enum { eDynamicFieldWidth = 100 }; + _dynamicFieldWidget->setSizePolicy(sizePolicy); + _dynamicFieldWidget->setFixedWidth(eDynamicFieldWidth); + _optionsPage->dynamicValueLayout->addWidget(_dynamicFieldWidget); +} + +void NotifyPluginOptionsPage::setDynamicFieldValue(NotificationItem* notification) +{ + if (QDoubleSpinBox* seValue = dynamic_cast(_dynamicFieldWidget)) + seValue->setValue(notification->singleValue().toDouble()); + else { + if (QComboBox* cbValue = dynamic_cast(_dynamicFieldWidget)) { + int idx = cbValue->findText(notification->singleValue().toString()); + if(-1 != idx) + cbValue->setCurrentIndex(idx); + } else { + if (QLineEdit* rangeValue = dynamic_cast(_dynamicFieldWidget)) { + QString str = QString("%1%2").arg(notification->singleValue().toDouble(), 5, 'f', 2, '0') + .arg(notification->valueRange2(), 5, 'f', 2, '0'); + rangeValue->setText(str); + } else { + qNotifyDebug() << "NotifyPluginOptionsPage::setDynamicValueField | unknown _fieldValue: " << _dynamicFieldWidget; + } + } + } +} + +void NotifyPluginOptionsPage::resetFieldType() +{ + _dynamicFieldType = -1; +} + +void NotifyPluginOptionsPage::getOptionsPageValues(NotificationItem* notification) +{ + Q_ASSERT(notification); + notification->setSoundCollectionPath(_optionsPage->SoundDirectoryPathChooser->path()); + notification->setCurrentLanguage(_optionsPage->SoundCollectionList->currentText()); + notification->setDataObject(_optionsPage->UAVObject->currentText()); + notification->setObjectField(_optionsPage->UAVObjectField->currentText()); + notification->setSound1(_optionsPage->Sound1->currentText()); + notification->setSound2(_optionsPage->Sound2->currentText()); + notification->setSound3(_optionsPage->Sound3->currentText()); + notification->setSayOrder(_sayOrder->currentText()); + notification->setRange(_dynamicFieldLimit->currentText()); + if (QDoubleSpinBox* spinValue = dynamic_cast(_dynamicFieldWidget)) + notification->setSingleValue(spinValue->value()); + else { + if (QComboBox* comboBoxValue = dynamic_cast(_dynamicFieldWidget)) + notification->setSingleValue(comboBoxValue->currentText()); + else { + if (QLineEdit* rangeValue = dynamic_cast(_dynamicFieldWidget)) { + QString str = rangeValue->text(); + QStringList range = str.split('-'); + notification->setSingleValue(range.at(0).toDouble()); + notification->setValueRange2(range.at(1).toDouble()); + } + } + } +} + +void NotifyPluginOptionsPage::updateConfigView(NotificationItem* notification) +{ + Q_ASSERT(notification); + disconnect(_optionsPage->UAVObject, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_UAVObject(QString))); + disconnect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_UAVField(QString))); + + QString path = notification->getSoundCollectionPath(); + if (path.isEmpty()) { + path = Utils::PathUtils().InsertDataPath("%%DATAPATH%%sounds"); + } + + _optionsPage->SoundDirectoryPathChooser->setPath(path); + + if (-1 != _optionsPage->SoundCollectionList->findText(notification->getCurrentLanguage())) { + _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText(notification->getCurrentLanguage())); + } else { + _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText("default")); + } + + // Fills the combo boxes for the UAVObjects + QList< QList > objList = _objManager.getDataObjects(); + foreach (QList list, objList) { + foreach (UAVDataObject* obj, list) { + _optionsPage->UAVObject->addItem(obj->getName()); + } + } + + if (-1 != _optionsPage->UAVObject->findText(notification->getDataObject())) { + _optionsPage->UAVObject->setCurrentIndex(_optionsPage->UAVObject->findText(notification->getDataObject())); + } + + _optionsPage->UAVObjectField->clear(); + if(_currUAVObject) { + QList fieldList = _currUAVObject->getFields(); + foreach (UAVObjectField* field, fieldList) + _optionsPage->UAVObjectField->addItem(field->getName()); + } + + if (-1 != _optionsPage->UAVObjectField->findText(notification->getObjectField())) { + _optionsPage->UAVObjectField->setCurrentIndex(_optionsPage->UAVObjectField->findText(notification->getObjectField())); + } + + if (-1 != _optionsPage->Sound1->findText(notification->getSound1())) { + _optionsPage->Sound1->setCurrentIndex(_optionsPage->Sound1->findText(notification->getSound1())); + } else { + // show item from default location + _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText("default")); + _optionsPage->Sound1->setCurrentIndex(_optionsPage->Sound1->findText(notification->getSound1())); + } + + if (-1 != _optionsPage->Sound2->findText(notification->getSound2())) { + _optionsPage->Sound2->setCurrentIndex(_optionsPage->Sound2->findText(notification->getSound2())); + } else { + // show item from default location + _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText("default")); + _optionsPage->Sound2->setCurrentIndex(_optionsPage->Sound2->findText(notification->getSound2())); + } + + if (-1 != _optionsPage->Sound3->findText(notification->getSound3())) { + _optionsPage->Sound3->setCurrentIndex(_optionsPage->Sound3->findText(notification->getSound3())); + } else { + // show item from default location + _optionsPage->SoundCollectionList->setCurrentIndex(_optionsPage->SoundCollectionList->findText("default")); + _optionsPage->Sound3->setCurrentIndex(_optionsPage->Sound3->findText(notification->getSound3())); + } + + if (-1 != _dynamicFieldLimit->findText(notification->range())) { + _dynamicFieldLimit->setCurrentIndex(_dynamicFieldLimit->findText(notification->range())); + } + + if (-1 != _sayOrder->findText(notification->getSayOrder())) { + _sayOrder->setCurrentIndex(_sayOrder->findText(notification->getSayOrder())); + } + + setDynamicFieldValue(notification); + + connect(_optionsPage->UAVObject, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_UAVObject(QString))); + connect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), + this, SLOT(on_changedIndex_UAVField(QString))); } -void NotifyPluginOptionsPage::changeButtonText(Phonon::State newstate, Phonon::State oldstate) +void NotifyPluginOptionsPage::on_changedIndex_rangeValue(QString rangeStr) { - if(newstate == Phonon::PausedState || newstate == Phonon::StoppedState){ - options_page->buttonPlayNotification->setText("Play"); - options_page->buttonPlayNotification->setIcon(QPixmap(":/notify/images/play.png")); - } - else - if(newstate == Phonon::PlayingState) { - options_page->buttonPlayNotification->setText("Stop"); - options_page->buttonPlayNotification->setIcon(QPixmap(":/notify/images/stop.png")); - } + Q_ASSERT(_dynamicFieldWidget); + UAVObjectField* field = getObjectFieldFromSelected(); + Q_ASSERT(!!field); + addDynamicFieldWidget(field); + setDynamicFieldValue(_selectedNotification); } - -void NotifyPluginOptionsPage::on_buttonTestSoundNotification_clicked() +void NotifyPluginOptionsPage::on_changedIndex_UAVField(QString field) { - // QList messageNotify; - NotifyPluginConfiguration *notification; - - if(notifyRulesSelection->currentIndex().row()==-1) return; - - notifySound->clearQueue(); - notification = privListNotifications.at(notifyRulesSelection->currentIndex().row()); - notification->parseNotifyMessage(); - foreach(QString item, notification->getNotifyMessageList()) - notifySound->enqueue(Phonon::MediaSource(item)); - notifySound->play(); -} - -void NotifyPluginOptionsPage::on_chkEnableSound_toggled(bool state) -{ - bool state1 = 1^state; - - QList listOutputs = notifySound->outputPaths(); - Phonon::AudioOutput * audioOutput = (Phonon::AudioOutput*)listOutputs.last().sink(); - audioOutput->setMuted(state1); -} - -void NotifyPluginOptionsPage::updateConfigView(NotifyPluginConfiguration* notification) -{ - QString path = notification->getSoundCollectionPath(); - if(path=="") - { - //QDir dir = QDir::currentPath(); - //path = QDir::currentPath().left(QDir::currentPath().indexOf("OpenPilot",0,Qt::CaseSensitive))+"../share/sounds"; - path = Utils::PathUtils().InsertDataPath("%%DATAPATH%%sounds"); - } - options_page->SoundDirectoryPathChooser->setPath(path); - - if(options_page->SoundCollectionList->findText(notification->getCurrentLanguage())!=-1){ - options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText(notification->getCurrentLanguage())); - } - else - options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); - - - if(options_page->UAVObject->findText(notification->getDataObject())!=-1){ - options_page->UAVObject->setCurrentIndex(options_page->UAVObject->findText(notification->getDataObject())); - } - - // Now load the object field values: - options_page->UAVObjectField->clear(); - QString uavDataObject = notification->getDataObject(); - UAVDataObject* obj = dynamic_cast( objManager->getObject(uavDataObject/*objList.at(0).at(0)->getName()*/) ); - if (obj != NULL ) { - QList fieldList = obj->getFields(); - foreach (UAVObjectField* field, fieldList) { - options_page->UAVObjectField->addItem(field->getName()); - } - } - - if(options_page->UAVObjectField->findText(notification->getObjectField())!=-1){ - options_page->UAVObjectField->setCurrentIndex(options_page->UAVObjectField->findText(notification->getObjectField())); - } - - if(options_page->Sound1->findText(notification->getSound1())!=-1){ - options_page->Sound1->setCurrentIndex(options_page->Sound1->findText(notification->getSound1())); - } - else - { - // show item from default location - options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); - options_page->Sound1->setCurrentIndex(options_page->Sound1->findText(notification->getSound1())); - - // don't show item if it wasn't find in stored location - //options_page->Sound1->setCurrentIndex(-1); - } - - if(options_page->Sound2->findText(notification->getSound2())!=-1) { - options_page->Sound2->setCurrentIndex(options_page->Sound2->findText(notification->getSound2())); - } - else { - // show item from default location - options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); - options_page->Sound2->setCurrentIndex(options_page->Sound2->findText(notification->getSound2())); - - // don't show item if it wasn't find in stored location - //options_page->Sound2->setCurrentIndex(-1); - } - - if(options_page->Sound3->findText(notification->getSound3())!=-1) { - options_page->Sound3->setCurrentIndex(options_page->Sound3->findText(notification->getSound3())); - } - else { - // show item from default location - options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); - options_page->Sound3->setCurrentIndex(options_page->Sound3->findText(notification->getSound3())); - } - - if(options_page->Value->findText(notification->getValue())!=-1) { - options_page->Value->setCurrentIndex(options_page->Value->findText(notification->getValue())); - } - - if(options_page->SayOrder->findText(notification->getSayOrder())!=-1) { - options_page->SayOrder->setCurrentIndex(options_page->SayOrder->findText(notification->getSayOrder())); - } - options_page->ValueSpinBox->setValue(notification->getSpinBoxValue()); -} - -void NotifyPluginOptionsPage::on_tableNotification_changeSelection( const QItemSelection & selected, const QItemSelection & deselected ) -{ - bool select = true; - notifySound->stop(); - if(selected.indexes().size()) - updateConfigView(privListNotifications.at(selected.indexes().at(0).row())); - else - select = false; - - options_page->buttonModify->setEnabled(select); - options_page->buttonDelete->setEnabled(select); - options_page->buttonPlayNotification->setEnabled(select); -} - - - -void NotifyPluginOptionsPage::on_buttonAddNotification_clicked() -{ - NotifyPluginConfiguration* notification = new NotifyPluginConfiguration; - - if(options_page->SoundDirectoryPathChooser->path()=="") - { - QPalette textPalette=options_page->SoundDirectoryPathChooser->palette(); - textPalette.setColor(QPalette::Normal,QPalette::Text, Qt::red); - options_page->SoundDirectoryPathChooser->setPalette(textPalette); - options_page->SoundDirectoryPathChooser->setPath("please select sound collection folder"); - return; - } - - notification->setSoundCollectionPath(options_page->SoundDirectoryPathChooser->path()); - notification->setCurrentLanguage(options_page->SoundCollectionList->currentText()); - notification->setDataObject(options_page->UAVObject->currentText()); - notification->setObjectField(options_page->UAVObjectField->currentText()); - notification->setValue(options_page->Value->currentText()); - notification->setSpinBoxValue(options_page->ValueSpinBox->value()); - - if(options_page->Sound1->currentText()!="") - notification->setSound1(options_page->Sound1->currentText()); - - notification->setSound2(options_page->Sound2->currentText()); - notification->setSound3(options_page->Sound3->currentText()); - - if(((options_page->Sound2->currentText()=="")&&(options_page->SayOrder->currentText()=="After second")) - || ((options_page->Sound3->currentText()=="")&&(options_page->SayOrder->currentText()=="After third"))) - return; - else - notification->setSayOrder(options_page->SayOrder->currentText()); - - privListNotifications.append(notification); - emit entryAdded(privListNotifications.size()-1); - notifyRulesSelection->setCurrentIndex(notifyRulesModel->index(privListNotifications.size()-1,0,QModelIndex()), - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); -} - - -void NotifyPluginOptionsPage::on_buttonDeleteNotification_clicked() -{ - notifyRulesModel->removeRow(notifyRulesSelection->currentIndex().row()); - if(!notifyRulesModel->rowCount() && (notifyRulesSelection->currentIndex().row() > 0 && notifyRulesSelection->currentIndex().row() < notifyRulesModel->rowCount())) - { - options_page->buttonDelete->setEnabled(false); - options_page->buttonModify->setEnabled(false); - options_page->buttonPlayNotification->setEnabled(false); - } + resetFieldType(); + Q_ASSERT(_currUAVObject); + addDynamicField(_currUAVObject->getField(field)); } -void NotifyPluginOptionsPage::on_buttonModifyNotification_clicked() +void NotifyPluginOptionsPage::on_changedIndex_UAVObject(QString val) { - NotifyPluginConfiguration* notification = new NotifyPluginConfiguration; - getOptionsPageValues(notification); - notification->setRepeatFlag(privListNotifications.at(notifyRulesSelection->currentIndex().row())->getRepeatFlag()); - privListNotifications.replace(notifyRulesSelection->currentIndex().row(),notification); - entryUpdated(notifyRulesSelection->currentIndex().row()); - + resetFieldType(); + _currUAVObject = dynamic_cast( _objManager.getObject(val) ); + if(!_currUAVObject) { + qNotifyDebug() << "on_UAVObject_indexChanged | no such UAVOBject"; + return; + } + QList fieldList = _currUAVObject->getFields(); + disconnect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_changedIndex_UAVField(QString))); + _optionsPage->UAVObjectField->clear(); + foreach (UAVObjectField* field, fieldList) { + _optionsPage->UAVObjectField->addItem(field->getName()); + } + connect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_changedIndex_UAVField(QString))); + _selectedNotification->setObjectField(fieldList.at(0)->getName()); + addDynamicField(fieldList.at(0)); } + +void NotifyPluginOptionsPage::on_changedIndex_soundLanguage(int index) +{ + _optionsPage->SoundCollectionList->setCurrentIndex(index); + QString collectionPath = _optionsPage->SoundDirectoryPathChooser->path() + + QDir::toNativeSeparators("/" + _optionsPage->SoundCollectionList->currentText()); + + QDir dirPath(collectionPath); + QStringList filters; + filters << "*.mp3" << "*.wav"; + dirPath.setNameFilters(filters); + QStringList listSoundFiles = dirPath.entryList(filters); + listSoundFiles.replaceInStrings(QRegExp(".mp3|.wav"), ""); + _optionsPage->Sound1->clear(); + _optionsPage->Sound2->clear(); + _optionsPage->Sound3->clear(); + _optionsPage->Sound1->addItems(listSoundFiles); + _optionsPage->Sound2->addItem(""); + _optionsPage->Sound2->addItems(listSoundFiles); + _optionsPage->Sound3->addItem(""); + _optionsPage->Sound3->addItems(listSoundFiles); +} + + +void NotifyPluginOptionsPage::on_changed_playButtonText(Phonon::State newstate, Phonon::State oldstate) +{ + //Q_ASSERT(Phonon::ErrorState != newstate); + + if (newstate == Phonon::PausedState || newstate == Phonon::StoppedState) { + _optionsPage->buttonPlayNotification->setText("Play"); + _optionsPage->buttonPlayNotification->setIcon(QPixmap(":/notify/images/play.png")); + } else { + if (newstate == Phonon::PlayingState) { + _optionsPage->buttonPlayNotification->setText("Stop"); + _optionsPage->buttonPlayNotification->setIcon(QPixmap(":/notify/images/stop.png")); + } + } +} + +void NotifyPluginOptionsPage::on_changedSelection_notifyTable(const QItemSelection & selected, const QItemSelection & deselected ) +{ + bool select = false; + _testSound->stop(); + if (selected.indexes().size()) { + select = true; + setSelectedNotification(_privListNotifications.at(selected.indexes().at(0).row())); + UAVObjectField* field = getObjectFieldFromSelected(); + addDynamicField(field); + updateConfigView(_selectedNotification); + } + + _optionsPage->buttonModify->setEnabled(select); + _optionsPage->buttonDelete->setEnabled(select); + _optionsPage->buttonPlayNotification->setEnabled(select); +} + +void NotifyPluginOptionsPage::on_clicked_buttonSoundFolder(const QString& path) +{ + QDir dirPath(path); + QStringList listDirCollections = dirPath.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + _optionsPage->SoundCollectionList->clear(); + _optionsPage->SoundCollectionList->addItems(listDirCollections); +} + +void NotifyPluginOptionsPage::on_clicked_buttonTestSoundNotification() +{ + NotificationItem* notification = NULL; + qNotifyDebug() << "on_buttonTestSoundNotification_clicked"; + Q_ASSERT(-1 != _notifyRulesSelection->currentIndex().row()); + _testSound->clearQueue(); + notification = _privListNotifications.at(_notifyRulesSelection->currentIndex().row()); + QStringList sequence = notification->toSoundList(); + if (sequence.isEmpty()) { + qNotifyDebug() << "message sequense is empty!"; + return; + } + foreach(QString item, sequence) { + qNotifyDebug() << item; + _testSound->enqueue(Phonon::MediaSource(item)); + } + _testSound->play(); +} + +void NotifyPluginOptionsPage::on_clicked_buttonAddNotification() +{ + NotificationItem* notification = new NotificationItem; + + if (_optionsPage->SoundDirectoryPathChooser->path().isEmpty()) { + QPalette textPalette=_optionsPage->SoundDirectoryPathChooser->palette(); + textPalette.setColor(QPalette::Normal,QPalette::Text, Qt::red); + _optionsPage->SoundDirectoryPathChooser->setPalette(textPalette); + _optionsPage->SoundDirectoryPathChooser->setPath("please select sound collection folder"); + delete notification; + return; + } + getOptionsPageValues(notification); + + if ( ((!_optionsPage->Sound2->currentText().isEmpty()) && (_sayOrder->currentText()=="After second")) + || ((!_optionsPage->Sound3->currentText().isEmpty()) && (_sayOrder->currentText()=="After third")) ) { + delete notification; + return; + } else { + notification->setSayOrder(_sayOrder->currentText()); + } + + _notifyRulesModel->entryAdded(notification); + _notifyRulesSelection->setCurrentIndex(_notifyRulesModel->index(_privListNotifications.size()-1,0,QModelIndex()), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); +} + +void NotifyPluginOptionsPage::on_clicked_buttonDeleteNotification() +{ + _notifyRulesModel->removeRow(_notifyRulesSelection->currentIndex().row()); + if (!_notifyRulesModel->rowCount() + && (_notifyRulesSelection->currentIndex().row() > 0 + && _notifyRulesSelection->currentIndex().row() < _notifyRulesModel->rowCount()) ) + { + _optionsPage->buttonDelete->setEnabled(false); + _optionsPage->buttonModify->setEnabled(false); + _optionsPage->buttonPlayNotification->setEnabled(false); + } +} + +void NotifyPluginOptionsPage::on_clicked_buttonModifyNotification() +{ + NotificationItem* notification = new NotificationItem; + getOptionsPageValues(notification); + notification->setRetryString(_privListNotifications.at(_notifyRulesSelection->currentIndex().row())->retryString()); + notification->setLifetime(_privListNotifications.at(_notifyRulesSelection->currentIndex().row())->lifetime()); + notification->setMute(_privListNotifications.at(_notifyRulesSelection->currentIndex().row())->mute()); + + _privListNotifications.replace(_notifyRulesSelection->currentIndex().row(),notification); + entryUpdated(_notifyRulesSelection->currentIndex().row()); +} + +void NotifyPluginOptionsPage::on_FinishedPlaying() +{ + _testSound->clear(); +} + +void NotifyPluginOptionsPage::on_toggled_checkEnableSound(bool state) +{ + bool state1 = 1^state; + + QList listOutputs = _testSound->outputPaths(); + Phonon::AudioOutput * audioOutput = (Phonon::AudioOutput*)listOutputs.last().sink(); + audioOutput->setMuted(state1); +} diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp.orig b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp.orig new file mode 100644 index 000000000..2ff775e31 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.cpp.orig @@ -0,0 +1,512 @@ +/** + ****************************************************************************** + * + * @file notifypluginoptionspage.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Notify Plugin options page + * @see The GNU Public License (GPL) Version 3 + * @defgroup notifyplugin + * @{ + * + *****************************************************************************/ +/* + * 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 3 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "notifypluginoptionspage.h" +#include +#include "notificationitem.h" +#include "ui_notifypluginoptionspage.h" +#include "extensionsystem/pluginmanager.h" +#include "utils/pathutils.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "notifyplugin.h" +#include "notifyitemdelegate.h" +#include "notifytablemodel.h" +#include "notifylogging.h" + +NotifyPluginOptionsPage::NotifyPluginOptionsPage(/*NotificationItem *config,*/ QObject *parent) + : IOptionsPage(parent) + , objManager(*ExtensionSystem::PluginManager::instance()->getObject()) + , owner(qobject_cast(parent)) + , currentCollectionPath("") +{ +} + +NotifyPluginOptionsPage::~NotifyPluginOptionsPage() +{ +} + +//creates options page widget (uses the UI file) +QWidget *NotifyPluginOptionsPage::createPage(QWidget *parent) +{ + options_page.reset(new Ui::NotifyPluginOptionsPage()); + //main widget + QWidget *optionsPageWidget = new QWidget; + //main layout + options_page->setupUi(optionsPageWidget); + + listSoundFiles.clear(); + + options_page->SoundDirectoryPathChooser->setExpectedKind(Utils::PathChooser::Directory); + options_page->SoundDirectoryPathChooser->setPromptDialogTitle(tr("Choose sound collection directory")); + + // Fills the combo boxes for the UAVObjects + QList< QList > objList = objManager.getDataObjects(); + foreach (QList list, objList) { + foreach (UAVDataObject* obj, list) { + options_page->UAVObject->addItem(obj->getName()); + } + } + +<<<<<<< Updated upstream + connect(options_page->SoundDirectoryPathChooser, SIGNAL(changed(const QString&)), this, SLOT(on_buttonSoundFolder_clicked(const QString&))); + connect(options_page->SoundCollectionList, SIGNAL(currentIndexChanged (int)), this, SLOT(on_soundLanguage_indexChanged(int))); + connect(options_page->UAVObject, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_UAVObject_indexChanged(QString))); +======= + options_page = new Ui::NotifyPluginOptionsPage(); + //main widget + QWidget *optionsPageWidget = new QWidget; + //main layout + options_page->setupUi(optionsPageWidget); + + delegateItems.clear(); + listSoundFiles.clear(); + + options_page->horizontalLayout_3->addWidget(new QPushButton("testtt")); + delegateItems << "Repeat Once" + << "Repeat Instantly" + << "Repeat 10 seconds" + << "Repeat 30 seconds" + << "Repeat 1 minute"; + + options_page->chkEnableSound->setChecked(owner->getEnableSound()); + options_page->SoundDirectoryPathChooser->setExpectedKind(Utils::PathChooser::Directory); + options_page->SoundDirectoryPathChooser->setPromptDialogTitle(tr("Choose sound collection directory")); + + + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + objManager = pm->getObject(); + + // Fills the combo boxes for the UAVObjects + QList< QList > objList = objManager->getDataObjects(); + foreach (QList list, objList) { + foreach (UAVDataObject* obj, list) { + options_page->UAVObject->addItem(obj->getName()); + } + } + + connect(options_page->SoundDirectoryPathChooser, SIGNAL(changed(const QString&)), this, SLOT(on_buttonSoundFolder_clicked(const QString&))); + connect(options_page->SoundCollectionList, SIGNAL(currentIndexChanged (int)), this, SLOT(on_soundLanguage_indexChanged(int))); + connect(options_page->buttonAdd, SIGNAL(pressed()), this, SLOT(on_buttonAddNotification_clicked())); + connect(options_page->buttonDelete, SIGNAL(pressed()), this, SLOT(on_buttonDeleteNotification_clicked())); + connect(options_page->buttonModify, SIGNAL(pressed()), this, SLOT(on_buttonModifyNotification_clicked())); +// connect(options_page->buttonTestSound1, SIGNAL(clicked()), this, SLOT(on_buttonTestSound1_clicked())); +// connect(options_page->buttonTestSound2, SIGNAL(clicked()), this, SLOT(on_buttonTestSound2_clicked())); + connect(options_page->buttonPlayNotification, SIGNAL(clicked()), this, SLOT(on_buttonTestSoundNotification_clicked())); + connect(options_page->chkEnableSound, SIGNAL(toggled(bool)), this, SLOT(on_chkEnableSound_toggled(bool))); + + + connect(options_page->UAVObject, SIGNAL(currentIndexChanged(QString)), this, SLOT(on_UAVObject_indexChanged(QString))); + connect(this, SIGNAL(updateNotifications(QList)), + owner, SLOT(updateNotificationList(QList))); + connect(this, SIGNAL(resetNotification()),owner, SLOT(resetNotification())); + + //emit resetNotification(); + + + privListNotifications.clear(); + + for (int i = 0; i < owner->getListNotifications().size(); ++i) { + NotifyPluginConfiguration* notification = new NotifyPluginConfiguration(); + owner->getListNotifications().at(i)->copyTo(notification); + privListNotifications.append(notification); + } + + updateConfigView(owner->getCurrentNotification()); + + options_page->chkEnableSound->setChecked(owner->getEnableSound()); + + QStringList headerStrings; + headerStrings << "Name" << "Repeats" << "Lifetime,sec"; +>>>>>>> Stashed changes + + connect(this, SIGNAL(updateNotifications(QList)), + owner, SLOT(updateNotificationList(QList))); + //connect(this, SIGNAL(resetNotification()),owner, SLOT(resetNotification())); + + +// privListNotifications = ((qobject_cast(parent))->getListNotifications()); + privListNotifications = owner->getListNotifications(); + + updateConfigView(owner->getCurrentNotification()); + + initRulesTable(); + initButtons(); + initPhononPlayer(); + + return optionsPageWidget; +} + +void NotifyPluginOptionsPage::initButtons() +{ + options_page->chkEnableSound->setChecked(owner->getEnableSound()); + connect(options_page->chkEnableSound, SIGNAL(toggled(bool)), this, SLOT(on_chkEnableSound_toggled(bool))); + + options_page->buttonModify->setEnabled(false); + options_page->buttonDelete->setEnabled(false); + options_page->buttonPlayNotification->setEnabled(false); + connect(options_page->buttonAdd, SIGNAL(pressed()), this, SLOT(on_buttonAddNotification_clicked())); + connect(options_page->buttonDelete, SIGNAL(pressed()), this, SLOT(on_buttonDeleteNotification_clicked())); + connect(options_page->buttonModify, SIGNAL(pressed()), this, SLOT(on_buttonModifyNotification_clicked())); + connect(options_page->buttonPlayNotification, SIGNAL(clicked()), this, SLOT(on_buttonTestSoundNotification_clicked())); +} + +void NotifyPluginOptionsPage::initPhononPlayer() +{ + notifySound.reset(Phonon::createPlayer(Phonon::NotificationCategory)); + connect(notifySound.data(),SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this,SLOT(changeButtonText(Phonon::State,Phonon::State))); + connect(notifySound.data(), SIGNAL(finished(void)), this, SLOT(onFinishedPlaying(void))); +} + +void NotifyPluginOptionsPage::initRulesTable() +{ + qNotifyDebug_if(_notifyRulesModel.isNull()) << "_notifyRulesModel.isNull())"; + qNotifyDebug_if(!_notifyRulesSelection) << "_notifyRulesSelection.isNull())"; + //QItemSelectionModel* selection = _notifyRulesSelection.take(); + _notifyRulesModel.reset(new NotifyTableModel(privListNotifications)); + _notifyRulesSelection = new QItemSelectionModel(_notifyRulesModel.data()); + + connect(_notifyRulesSelection, SIGNAL(selectionChanged ( const QItemSelection &, const QItemSelection & )), + this, SLOT(on_tableNotification_changeSelection( const QItemSelection & , const QItemSelection & ))); + connect(this, SIGNAL(entryUpdated(int)), + _notifyRulesModel.data(), SLOT(entryUpdated(int))); + connect(this, SIGNAL(entryAdded(int)), + _notifyRulesModel.data(), SLOT(entryAdded(int))); + + options_page->notifyRulesView->setModel(_notifyRulesModel.data()); + options_page->notifyRulesView->setSelectionModel(_notifyRulesSelection); + options_page->notifyRulesView->setItemDelegate(new NotifyItemDelegate(this)); + + options_page->notifyRulesView->resizeRowsToContents(); + options_page->notifyRulesView->setColumnWidth(eMESSAGE_NAME,200); + options_page->notifyRulesView->setColumnWidth(eREPEAT_VALUE,120); + options_page->notifyRulesView->setColumnWidth(eEXPIRE_TIME,100); + options_page->notifyRulesView->setColumnWidth(eENABLE_NOTIFICATION,60); + options_page->notifyRulesView->setDragEnabled(true); + options_page->notifyRulesView->setAcceptDrops(true); + options_page->notifyRulesView->setDropIndicatorShown(true); + options_page->notifyRulesView->setDragDropMode(QAbstractItemView::InternalMove); + + +} + +void NotifyPluginOptionsPage::getOptionsPageValues(NotificationItem* notification) +{ + notification->setSoundCollectionPath(options_page->SoundDirectoryPathChooser->path()); + notification->setCurrentLanguage(options_page->SoundCollectionList->currentText()); + notification->setDataObject(options_page->UAVObject->currentText()); + notification->setObjectField(options_page->UAVObjectField->currentText()); + notification->setSound1(options_page->Sound1->currentText()); + notification->setSound2(options_page->Sound2->currentText()); + notification->setSound3(options_page->Sound3->currentText()); + notification->setSayOrder(options_page->SayOrder->currentText()); + notification->setValue(options_page->Value->currentText()); + notification->setSpinBoxValue(options_page->ValueSpinBox->value()); +} + +/*! +* Called when the user presses apply or OK. +* Saves the current values +*/ +void NotifyPluginOptionsPage::apply() +{ + getOptionsPageValues(owner->getCurrentNotification()); + owner->setEnableSound(options_page->chkEnableSound->isChecked()); + emit updateNotifications(privListNotifications); +} + +void NotifyPluginOptionsPage::finish() +{ + disconnect(notifySound.data(),SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this,SLOT(changeButtonText(Phonon::State,Phonon::State))); + if (notifySound) { + notifySound->stop(); + notifySound->clear(); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Fills in the combo box when value is changed in the +// combo box +////////////////////////////////////////////////////////////////////////////// +void NotifyPluginOptionsPage::on_UAVObject_indexChanged(QString val) { + options_page->UAVObjectField->clear(); + ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager* objManager = pm->getObject(); + UAVDataObject* obj = dynamic_cast( objManager->getObject(val) ); + QList fieldList = obj->getFields(); + foreach (UAVObjectField* field, fieldList) { + options_page->UAVObjectField->addItem(field->getName()); + } +} + +// locate collection folder on disk +void NotifyPluginOptionsPage::on_buttonSoundFolder_clicked(const QString& path) +{ + QDir dirPath(path); + listDirCollections = dirPath.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + options_page->SoundCollectionList->clear(); + options_page->SoundCollectionList->addItems(listDirCollections); +} + + +void NotifyPluginOptionsPage::on_soundLanguage_indexChanged(int index) +{ + options_page->SoundCollectionList->setCurrentIndex(index); + + currentCollectionPath = options_page->SoundDirectoryPathChooser->path() + + QDir::toNativeSeparators("/" + options_page->SoundCollectionList->currentText()); + + QDir dirPath(currentCollectionPath); + QStringList filters; + filters << "*.mp3" << "*.wav"; + dirPath.setNameFilters(filters); + listSoundFiles = dirPath.entryList(filters); + listSoundFiles.replaceInStrings(QRegExp(".mp3|.wav"), ""); + options_page->Sound1->clear(); + options_page->Sound2->clear(); + options_page->Sound3->clear(); + options_page->Sound1->addItems(listSoundFiles); + options_page->Sound2->addItem(""); + options_page->Sound2->addItems(listSoundFiles); + options_page->Sound3->addItem(""); + options_page->Sound3->addItems(listSoundFiles); + +} + +void NotifyPluginOptionsPage::changeButtonText(Phonon::State newstate, Phonon::State oldstate) +{ + //Q_ASSERT(Phonon::ErrorState != newstate); + + if (newstate == Phonon::PausedState || newstate == Phonon::StoppedState) { + options_page->buttonPlayNotification->setText("Play"); + options_page->buttonPlayNotification->setIcon(QPixmap(":/notify/images/play.png")); + } else { + if (newstate == Phonon::PlayingState) { + options_page->buttonPlayNotification->setText("Stop"); + options_page->buttonPlayNotification->setIcon(QPixmap(":/notify/images/stop.png")); + } + } +} + +void NotifyPluginOptionsPage::onFinishedPlaying() +{ + notifySound->clear(); +} + +void NotifyPluginOptionsPage::on_buttonTestSoundNotification_clicked() +{ + NotificationItem* notification = NULL; + + if (-1 == _notifyRulesSelection->currentIndex().row()) + return; + notifySound->clearQueue(); + notification = privListNotifications.at(_notifyRulesSelection->currentIndex().row()); + notification->parseNotifyMessage(); + QStringList sequence = notification->getMessageSequence(); + Q_ASSERT(!!sequence.size()); + foreach(QString item, sequence) + notifySound->enqueue(Phonon::MediaSource(item)); + + notifySound->play(); +} + +void NotifyPluginOptionsPage::on_chkEnableSound_toggled(bool state) +{ + bool state1 = 1^state; + + QList listOutputs = notifySound->outputPaths(); + Phonon::AudioOutput * audioOutput = (Phonon::AudioOutput*)listOutputs.last().sink(); + audioOutput->setMuted(state1); +} + +void NotifyPluginOptionsPage::updateConfigView(NotificationItem* notification) +{ + QString path = notification->getSoundCollectionPath(); + if (path == "") { + //QDir dir = QDir::currentPath(); + //path = QDir::currentPath().left(QDir::currentPath().indexOf("OpenPilot",0,Qt::CaseSensitive))+"../share/sounds"; + path = Utils::PathUtils().InsertDataPath("%%DATAPATH%%sounds"); + } + + options_page->SoundDirectoryPathChooser->setPath(path); + + if (-1 != options_page->SoundCollectionList->findText(notification->getCurrentLanguage())){ + options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText(notification->getCurrentLanguage())); + } else { + options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); + } + + if (options_page->UAVObject->findText(notification->getDataObject())!=-1){ + options_page->UAVObject->setCurrentIndex(options_page->UAVObject->findText(notification->getDataObject())); + } + + // Now load the object field values: + options_page->UAVObjectField->clear(); + QString uavDataObject = notification->getDataObject(); + UAVDataObject* obj = dynamic_cast(objManager.getObject(uavDataObject)); + if (obj != NULL ) { + QList fieldList = obj->getFields(); + foreach (UAVObjectField* field, fieldList) { + options_page->UAVObjectField->addItem(field->getName()); + } + } + + if (-1 != options_page->UAVObjectField->findText(notification->getObjectField())) { + options_page->UAVObjectField->setCurrentIndex(options_page->UAVObjectField->findText(notification->getObjectField())); + } + + if (-1 != options_page->Sound1->findText(notification->getSound1())) { + options_page->Sound1->setCurrentIndex(options_page->Sound1->findText(notification->getSound1())); + } else { + // show item from default location + options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); + options_page->Sound1->setCurrentIndex(options_page->Sound1->findText(notification->getSound1())); + + // don't show item if it wasn't find in stored location + //options_page->Sound1->setCurrentIndex(-1); + } + + if (-1 != options_page->Sound2->findText(notification->getSound2())) { + options_page->Sound2->setCurrentIndex(options_page->Sound2->findText(notification->getSound2())); + } else { + // show item from default location + options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); + options_page->Sound2->setCurrentIndex(options_page->Sound2->findText(notification->getSound2())); + + // don't show item if it wasn't find in stored location + //options_page->Sound2->setCurrentIndex(-1); + } + + if (-1 != options_page->Sound3->findText(notification->getSound3())) { + options_page->Sound3->setCurrentIndex(options_page->Sound3->findText(notification->getSound3())); + } else { + // show item from default location + options_page->SoundCollectionList->setCurrentIndex(options_page->SoundCollectionList->findText("default")); + options_page->Sound3->setCurrentIndex(options_page->Sound3->findText(notification->getSound3())); + } + + if (-1 != options_page->Value->findText(notification->getValue())) { + options_page->Value->setCurrentIndex(options_page->Value->findText(notification->getValue())); + } + + if (-1 != options_page->SayOrder->findText(notification->getSayOrder())) { + options_page->SayOrder->setCurrentIndex(options_page->SayOrder->findText(notification->getSayOrder())); + } + + options_page->ValueSpinBox->setValue(notification->getSpinBoxValue()); +} + +void NotifyPluginOptionsPage::on_tableNotification_changeSelection( const QItemSelection & selected, const QItemSelection & deselected ) +{ + bool select = false; + notifySound->stop(); + if (selected.indexes().size()) { + select = true; + updateConfigView(privListNotifications.at(selected.indexes().at(0).row())); + } + + options_page->buttonModify->setEnabled(select); + options_page->buttonDelete->setEnabled(select); + options_page->buttonPlayNotification->setEnabled(select); +} + + +void NotifyPluginOptionsPage::on_buttonAddNotification_clicked() +{ + NotificationItem* notification = new NotificationItem; + + if (options_page->SoundDirectoryPathChooser->path()=="") { + QPalette textPalette=options_page->SoundDirectoryPathChooser->palette(); + textPalette.setColor(QPalette::Normal,QPalette::Text, Qt::red); + options_page->SoundDirectoryPathChooser->setPalette(textPalette); + options_page->SoundDirectoryPathChooser->setPath("please select sound collection folder"); + return; + } + + notification->setSoundCollectionPath(options_page->SoundDirectoryPathChooser->path()); + notification->setCurrentLanguage(options_page->SoundCollectionList->currentText()); + notification->setDataObject(options_page->UAVObject->currentText()); + notification->setObjectField(options_page->UAVObjectField->currentText()); + notification->setValue(options_page->Value->currentText()); + notification->setSpinBoxValue(options_page->ValueSpinBox->value()); + + if (options_page->Sound1->currentText().size() > 0) + notification->setSound1(options_page->Sound1->currentText()); + + notification->setSound2(options_page->Sound2->currentText()); + notification->setSound3(options_page->Sound3->currentText()); + +if ( ((!options_page->Sound2->currentText().size()) && (options_page->SayOrder->currentText()=="After second")) + || ((!options_page->Sound3->currentText().size()) && (options_page->SayOrder->currentText()=="After third")) ) { + return; + } else { + notification->setSayOrder(options_page->SayOrder->currentText()); + } + privListNotifications.append(notification); + emit entryAdded(privListNotifications.size() - 1); + _notifyRulesSelection->setCurrentIndex(_notifyRulesModel->index(privListNotifications.size()-1,0,QModelIndex()), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); +} + + +void NotifyPluginOptionsPage::on_buttonDeleteNotification_clicked() +{ + _notifyRulesModel->removeRow(_notifyRulesSelection->currentIndex().row()); + if (!_notifyRulesModel->rowCount() + && (_notifyRulesSelection->currentIndex().row() > 0 + && _notifyRulesSelection->currentIndex().row() < _notifyRulesModel->rowCount()) ) + { + options_page->buttonDelete->setEnabled(false); + options_page->buttonModify->setEnabled(false); + options_page->buttonPlayNotification->setEnabled(false); + } + +} + +void NotifyPluginOptionsPage::on_buttonModifyNotification_clicked() +{ + NotificationItem* notification = new NotificationItem; + getOptionsPageValues(notification); + notification->setRetryString(privListNotifications.at(_notifyRulesSelection->currentIndex().row())->retryString()); + notification->setLifetime(privListNotifications.at(_notifyRulesSelection->currentIndex().row())->lifetime()); + notification->setMute(privListNotifications.at(_notifyRulesSelection->currentIndex().row())->mute()); + + privListNotifications.replace(_notifyRulesSelection->currentIndex().row(),notification); + entryUpdated(_notifyRulesSelection->currentIndex().row()); + +} + diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.h b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.h index 9d159e2a4..b270e72a0 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.h +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.h @@ -42,83 +42,145 @@ #include #include #include +#include +#include class NotifyTableModel; - -class NotifyPluginConfiguration; +class NotificationItem; class SoundNotifyPlugin; namespace Ui { - class NotifyPluginOptionsPage; -} - + class NotifyPluginOptionsPage; +}; using namespace Core; class NotifyPluginOptionsPage : public IOptionsPage { - Q_OBJECT + Q_OBJECT + public: - explicit NotifyPluginOptionsPage(/*NotifyPluginConfiguration *config, */QObject *parent = 0); - - QString id() const { return QLatin1String("settings"); } - QString trName() const { return tr("settings"); } - QString category() const { return QLatin1String("Notify Plugin");} - QString trCategory() const { return tr("Notify Plugin");} - + explicit NotifyPluginOptionsPage(QObject *parent = 0); + ~NotifyPluginOptionsPage(); + QString id() const { return QLatin1String("settings"); } + QString trName() const { return tr("settings"); } + QString category() const { return QLatin1String("Notify Plugin");} + QString trCategory() const { return tr("Notify Plugin");} QWidget *createPage(QWidget *parent); void apply(); - void finish(); - void restoreFromSettings(); - - void updateConfigView(NotifyPluginConfiguration* notification); - void getOptionsPageValues(NotifyPluginConfiguration* notification); - -private: - UAVObjectManager *objManager; - SoundNotifyPlugin* owner; - QStringList listDirCollections; - QStringList listSoundFiles; - QString currentCollectionPath; - int sizeNotifyList; - Phonon::MediaObject *sound1; - Phonon::MediaObject *sound2; - Phonon::MediaObject *notifySound; - Phonon::AudioOutput *audioOutput; - QStringList delegateItems; - NotifyTableModel* notifyRulesModel; - QItemSelectionModel *notifyRulesSelection; - QList privListNotifications; - - Ui::NotifyPluginOptionsPage *options_page; - //NotifyPluginConfiguration *notify; + void finish(); + void restoreFromSettings(); signals: - void updateNotifications(QList list); - void resetNotification(void); - void entryUpdated(int index); - void entryAdded(int position); - + void updateNotifications(QList list); + void entryUpdated(int index); private slots: - void showPersistentComboBox( const QModelIndex & parent, int start, int end ); - void showPersistentComboBox2 ( const QModelIndex & topLeft, const QModelIndex & bottomRight ); + void on_clicked_buttonTestSoundNotification(); + void on_clicked_buttonAddNotification(); + void on_clicked_buttonDeleteNotification(); + void on_clicked_buttonModifyNotification(); -// void on_buttonTestSound1_clicked(); -// void on_buttonTestSound2_clicked(); - void on_buttonTestSoundNotification_clicked(); + /** + * We can use continuous selection, to select simultaneously + * multiple rows to move them(using drag & drop) inside table ranges. + */ + void on_changedSelection_notifyTable( const QItemSelection & selected, const QItemSelection & deselected ); + + void on_changedIndex_soundLanguage(int index); + void on_clicked_buttonSoundFolder(const QString& path); + void on_changedIndex_UAVObject(QString val); + void on_changedIndex_UAVField(QString val); + void on_changed_playButtonText(Phonon::State newstate, Phonon::State oldstate); + void on_toggled_checkEnableSound(bool state); + + /** + * Important when we change to or from "In range" value + * For enums UI layout stayed the same, but for numeric values + * we need to change UI to show edit line, + * to have possibility assign range limits for value. + */ + void on_changedIndex_rangeValue(QString); + + void on_FinishedPlaying(void); + + +private: + Q_DISABLE_COPY(NotifyPluginOptionsPage) + + void initButtons(); + void initPhononPlayer(); + void initRulesTable(); + + void setSelectedNotification(NotificationItem* ntf); + void resetValueRange(); + void resetFieldType(); + + void updateConfigView(NotificationItem* notification); + void getOptionsPageValues(NotificationItem* notification); + UAVObjectField* getObjectFieldFromPage(); + UAVObjectField* getObjectFieldFromSelected(); + + void addDynamicFieldLayout(); + void addDynamicField(UAVObjectField* objField); + void addDynamicFieldWidget(UAVObjectField* objField); + void setDynamicFieldValue(NotificationItem* notification); + +private: + + UAVObjectManager& _objManager; + SoundNotifyPlugin* _owner; + + //! Media object uses to test sound playing + QScopedPointer _testSound; + + QScopedPointer _notifyRulesModel; + QItemSelectionModel* _notifyRulesSelection; + + /** + * Local copy of notification list, which owned by notify plugin. + * Notification list readed once on application loaded, during + * notify plugin startup, then on open options page. + * This copy is simple assignment, but due to implicitly sharing + * we don't have additional cost for that, copy will created + * only after modification of private notify list. + */ + QList _privListNotifications; + + QScopedPointer _optionsPage; + + //! Widget to convinient selection of condition for field value (equal, lower, greater) + QComboBox* _dynamicFieldLimit; + + //! Represents edit widget for dynamic UAVObjectfield, + //! can be spinbox - for numerics, combobox - enums, or + //! lineedit - for numerics with range constraints + QWidget* _dynamicFieldWidget; + + //! Type of UAVObjectField - numeric or ENUM, + //! this variable needs to correctly set appropriate dynamic UI element (_dynamicFieldWidget) + //! NOTE: ocassionaly it should be invalidated (= -1) to reset _dynamicFieldWidget + int _dynamicFieldType; + + //! Widget to convinient selection of position of + //! between sounds[1..3] + QComboBox* _sayOrder; + + //! Actualy reference to optionsPageWidget, + //! we MUST hold it beyond the scope of createPage func + //! to have possibility change dynamic parts of options page layout in future + QWidget* _form; + + //! Currently selected notification, all controls filled accroding to it. + //! On options page startup, always points to first row. + NotificationItem* _selectedNotification; + + //! Retrieved from UAVObjectManager by name from _selectedNotification, + //! if UAVObjectManager doesn't have such object, this field will be NULL + UAVDataObject* _currUAVObject; - void on_buttonAddNotification_clicked(); - void on_buttonDeleteNotification_clicked(); - void on_buttonModifyNotification_clicked(); - void on_tableNotification_changeSelection( const QItemSelection & selected, const QItemSelection & deselected ); - void on_soundLanguage_indexChanged(int index); - void on_buttonSoundFolder_clicked(const QString& path); - void on_UAVObject_indexChanged(QString val); - void changeButtonText(Phonon::State newstate, Phonon::State oldstate); - void on_chkEnableSound_toggled(bool state); }; #endif // NOTIFYPLUGINOPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui index b3f48432a..94560ff1a 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/notify/notifypluginoptionspage.ui @@ -6,7 +6,7 @@ 0 0 - 589 + 570 453 @@ -19,531 +19,364 @@ Form - - - - 10 - 10 - 501 - 81 - + + + QLayout::SetMinimumSize - - Sound Collection - - - - - 10 - 20 - 481 - 51 - - - - - 6 + + + + QLayout::SetFixedSize - - - - Language + + + + + 0 + 0 + - - - - - - true + + Sound Collection - - - 75 - 23 - - - - - - - - - 147 - 0 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + true + + + + 75 + 23 + + + + + 550 + 16777215 + + + + + + + + + 0 + 0 + + + + Language + + + + + + + + 147 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Select the sound collection</span></p></body></html> + + + + + + + + + + + + + + + + + DataObject + + + + + + + + 0 + 0 + + + + + + + + ObjectField + + + + + + + + 0 + 0 + - - - - - - 10 - 220 - 501 - 211 - - - - Sound Notifications - - - - - 10 - 180 - 481 - 26 - - - + + + + + Qt::Horizontal + + + + + + + + - + + + + 0 + 0 + + - Enable Sounds + Sound1: - - - Qt::Horizontal + + + + 0 + 0 + - + - 138 - 20 + 110 + 0 - - - - - - Play - - - - :/notify/images/play.png:/notify/images/play.png - - - - - - - Qt::Horizontal - - + - 40 - 20 + 16777215 + 16777215 - + - - - Qt::Horizontal + + + + 0 + 0 + - + + Sound2: + + + + + + + + 0 + 0 + + + - 40 - 20 + 110 + 0 - - - - - - Add - - - - :/notify/images/add.png:/notify/images/add.png + + + 16777215 + 16777215 + - - - Modify + + + + 0 + 0 + - - - :/notify/images/modify.png:/notify/images/modify.png + + Sound3: - - - Delete + + + + 0 + 0 + - - - :/utils/images/removesubmitfield.png:/utils/images/removesubmitfield.png + + + 110 + 0 + + + + + 16777215 + 16777215 + - - - - - 10 - 20 - 481 - 151 - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - 22 - - - 22 - - - - - - - 10 - 100 - 501 - 31 - - - - - - - DataObject - - - - - - - - 0 - 0 - - - - - - - - ObjectField - - - - - - - - 0 - 0 - - - - - - - - - - 7 - 130 - 501 - 20 - - - - Qt::Horizontal - - - - - - 10 - 180 - 501 - 31 - - - - - - - - 0 - 0 - - - - Sound1: - - - - - - - - 0 - 0 - - - - - 110 - 0 - - - - - 16777215 - 16777215 - - - - - - - - Sound2: - - - - - - - - 0 - 0 - - - - - 110 - 0 - - - - - 16777215 - 16777215 - - - - - - - - Sound3: - - - - - - - - 0 - 0 - - - - - 110 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - 10 - 150 - 501 - 31 - - - - - - - true - - - - 0 - 0 - - - - - 40 - 0 - - - - Value is - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 110 - 16777215 - - + + + + + + + + Sound Notifications + + - - Equal to - + + + QAbstractItemView::ContiguousSelection + + + QAbstractItemView::SelectRows + + + 22 + + + 22 + + - - Greater than - + + + + + Enable Sounds + + + + + + + Qt::Horizontal + + + + 138 + 20 + + + + + + + + Play + + + + :/notify/images/play.png:/notify/images/play.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add + + + + :/notify/images/add.png:/notify/images/add.png + + + + + + + Modify + + + + :/notify/images/modify.png:/notify/images/modify.png + + + + + + + Delete + + + + :/utils/images/removesubmitfield.png:/utils/images/removesubmitfield.png + + + + - - - Less than - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 170 - 16777215 - - - - 2 - - - 9999.899999999999636 - - - 1.000000000000000 - - - - - - - - 0 - 0 - - - - Say Order - - - - - - - - 0 - 0 - - - - - 110 - 16777215 - - - - Select if the value of the object should be spoken and if so, either before the configured sound or after it. - - - - Never - - - - - Before first - - - - - After first - - - - - After second - - - - - After third - - - - - - + + + + diff --git a/ground/openpilotgcs/src/plugins/notify/notifytablemodel.cpp b/ground/openpilotgcs/src/plugins/notify/notifytablemodel.cpp index 6f0584d70..ed4eb0e56 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifytablemodel.cpp +++ b/ground/openpilotgcs/src/plugins/notify/notifytablemodel.cpp @@ -26,110 +26,239 @@ */ #include "notifytablemodel.h" +#include "notifylogging.h" +#include +#include + +const char* mime_type_notify_table = "openpilot/notify_plugin_table"; + +NotifyTableModel::NotifyTableModel(QList& parentList, QObject* parent) + : QAbstractTableModel(parent) + , _list(parentList) +{ + _headerStrings << "Name" << "Repeats" << "Lifetime,sec" << "Mute"; + connect(this, SIGNAL(dragRows(int, int)), this, SLOT(dropRows(int, int))); +} + bool NotifyTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (index.isValid() && role == Qt::EditRole) { - if(index.column()==1) - _list->at(index.row())->setRepeatFlag(value.toString()); - else - if(index.column()==2) - _list->at(index.row())->setExpireTimeout(value.toInt()); - - emit dataChanged(index, index); - return true; - } - return false; + if (index.isValid() && role == Qt::DisplayRole) { + if (eMessageName == index.column()) { + emit dataChanged(index, index); + return true; + } + } + if (index.isValid() && role == Qt::EditRole) { + if (eRepeatValue == index.column()) + _list.at(index.row())->setRetryString(value.toString()); + else { + if (eExpireTimer == index.column()) + _list.at(index.row())->setLifetime(value.toInt()); + else { + if (eTurnOn == index.column()) + _list.at(index.row())->setMute(value.toBool()); + } + } + emit dataChanged(index, index); + return true; + } + return false; } QVariant NotifyTableModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) { + qWarning() << "NotifyTableModel::data - index.isValid()"; + return QVariant(); + } - if (!index.isValid()) - return QVariant(); + if (index.row() >= _list.size()) + return QVariant(); - if (index.row() >= _list->size()) - return QVariant(); + if (role == Qt::DisplayRole || role == Qt::EditRole) + { + switch(index.column()) + { + case eMessageName: + return _list.at(index.row())->toString(); - if (role == Qt::DisplayRole || role == Qt::EditRole) - { - switch(index.column()) - { - case 0: - return _list->at(index.row())->parseNotifyMessage(); + case eRepeatValue: + return _list.at(index.row())->retryString(); - case 1: - return _list->at(index.row())->getRepeatFlag(); + case eExpireTimer: + return _list.at(index.row())->lifetime(); - case 2: - return _list->at(index.row())->getExpireTimeout(); + case eTurnOn: + return _list.at(index.row())->mute(); - default: - return QVariant(); - } - } - else - { - if (Qt::SizeHintRole == role){ - //QVariant size = data(index, Qt::SizeHintRole); - return QVariant(10); - } - // if(role == Qt::DecorationRole) - // if (index.column() == 0) - // return defectsIcons[defectList->at(index.row()).id-1]; - } - return QVariant(); + default: + return QVariant(); + } + } + else + { + if (Qt::SizeHintRole == role){ + return QVariant(10); + } + } + return QVariant(); } QVariant NotifyTableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role != Qt::DisplayRole) - return QVariant(); + if (role != Qt::DisplayRole) + return QVariant(); - if (orientation == Qt::Horizontal) - return headerStrings.at(section); - else - if(orientation == Qt::Vertical) - return QString("%1").arg(section); + if (orientation == Qt::Horizontal) + return _headerStrings.at(section); + else + if (orientation == Qt::Vertical) + return QString("%1").arg(section); - return QVariant(); + return QVariant(); } -bool NotifyTableModel::insertRows(int position, int rows, const QModelIndex &index) +bool NotifyTableModel::insertRows(int position, int rows, const QModelIndex& index) { - Q_UNUSED(index); - beginInsertRows(QModelIndex(), position, position+rows-1); + Q_UNUSED(index); -// for (int row=0; row < rows; ++row) { -// _list->append(position); -// } + if (-1 == position || -1 == rows) + return false; + beginInsertRows(QModelIndex(), position, position + rows - 1); - endInsertRows(); - return true; + for (int i = 0; i < rows; ++i) { + _list.insert(position + i, new NotificationItem()); + } + + endInsertRows(); + return true; } - bool NotifyTableModel::removeRows(int position, int rows, const QModelIndex &index) - { - Q_UNUSED(index); - beginRemoveRows(QModelIndex(), position, position+rows-1); +bool NotifyTableModel::removeRows(int position, int rows, const QModelIndex& index) +{ + Q_UNUSED(index); - for (int row=0; row < rows; ++row) { - _list->removeAt(position); - } + if ((-1 == position) || (-1 == rows) ) + return false; - endRemoveRows(); - return true; - } + beginRemoveRows(QModelIndex(), position, position + rows - 1); + + for (int row = 0; row < rows; ++row) { + _list.removeAt(position); + } + + endRemoveRows(); + return true; +} void NotifyTableModel::entryUpdated(int offset) { - QModelIndex idx = index(offset, 0); - emit dataChanged(idx, idx); + QModelIndex idx = index(offset, 0); + emit dataChanged(idx, idx); } -void NotifyTableModel::entryAdded(int position) +void NotifyTableModel::entryAdded(NotificationItem* item) { - insertRows(position, 1,QModelIndex()); + insertRows(rowCount(), 1, QModelIndex()); + NotificationItem* tmp = _list.at(rowCount() - 1); + _list.replace(rowCount() - 1, item); + delete tmp; + entryUpdated(rowCount() - 1); +} + +Qt::DropActions NotifyTableModel::supportedDropActions() const +{ + return Qt::MoveAction; +} + +QStringList NotifyTableModel::mimeTypes() const +{ + QStringList types; + types << mime_type_notify_table; + return types; +} + +bool NotifyTableModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, + int column, const QModelIndex& parent) +{ + if (action == Qt::IgnoreAction) + return true; + + if (!data->hasFormat(mime_type_notify_table)) + return false; + + int beginRow = -1; + + if (row != -1) + beginRow = row; + else { + if (parent.isValid()) + beginRow = parent.row(); + else + beginRow = rowCount(QModelIndex()); + } + + if (-1 == beginRow) + return false; + + QByteArray encodedData = data->data(mime_type_notify_table); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + int rows = beginRow; + // read next item from input MIME and drop into the table line by line + while(!stream.atEnd()) { + qint32 ptr; + stream >> ptr; + NotificationItem* item = reinterpret_cast(ptr); + int dragged = _list.indexOf(item); + // we can drag item from top rows to bottom (DOWN_DIRECTION), + // or from bottom rows to top rows (UP_DIRECTION) + enum { UP_DIRECTION, DOWN_DIRECTION }; + int direction = (dragged < rows) ? DOWN_DIRECTION : (dragged += 1, UP_DIRECTION); + // check drop bounds + if (dragged < 0 || ((dragged + 1) >= _list.size() && direction == DOWN_DIRECTION) || dragged == rows) { + qNotifyDebug() << "no such item"; + continue; + } + // addiional check in case dropping of multiple rows + if(rows + direction > _list.size()) continue; + + Q_ASSERT(insertRows(rows + direction, 1, QModelIndex())); + _list.replace(rows + direction, item); + Q_ASSERT(removeRows(dragged, 1, QModelIndex())); + if (direction == UP_DIRECTION) + ++rows; + }; + + QModelIndex idxTopLeft = index(beginRow, 0, QModelIndex()); + QModelIndex idxBotRight = index(beginRow, columnCount(QModelIndex()), QModelIndex()); + emit dataChanged(idxTopLeft, idxBotRight); + return true; +} + +QMimeData* NotifyTableModel::mimeData(const QModelIndexList& indexes) const +{ + QMimeData* mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + int rows = 0; + foreach (const QModelIndex& index, indexes) { + if (!index.column()) { + qint32 item = reinterpret_cast(_list.at(index.row())); + stream << item; + ++rows; + } + } + mimeData->setData(mime_type_notify_table, encodedData); + return mimeData; +} + +void NotifyTableModel::dropRows(int position, int count) const +{ + for (int row = 0; row < count; ++row) { + _list.removeAt(position); + } } diff --git a/ground/openpilotgcs/src/plugins/notify/notifytablemodel.h b/ground/openpilotgcs/src/plugins/notify/notifytablemodel.h index 65aa82a86..28eb8cc68 100644 --- a/ground/openpilotgcs/src/plugins/notify/notifytablemodel.h +++ b/ground/openpilotgcs/src/plugins/notify/notifytablemodel.h @@ -31,49 +31,60 @@ #include #include -#include "notifypluginconfiguration.h" +#include "notificationitem.h" + +enum ColumnNames { eMessageName, eRepeatValue, eExpireTimer, eTurnOn }; class NotifyTableModel : public QAbstractTableModel { - Q_OBJECT - public: - NotifyTableModel(QList *parentList, const QStringList& parentHeaderList, QObject *parent = 0) - : QAbstractTableModel(parent), - _list(parentList), - headerStrings(parentHeaderList) - { } + Q_OBJECT - int rowCount(const QModelIndex &parent = QModelIndex()) const - { - return _list->count(); - } + enum {eColumnCount = 4 }; - int columnCount(const QModelIndex &/*parent*/) const - { - return 3; - } +public: - Qt::ItemFlags flags(const QModelIndex &index) const - { - if (!index.isValid()) - return Qt::ItemIsEnabled; + NotifyTableModel(QList& parentList, QObject* parent = 0); + int rowCount(const QModelIndex& parent = QModelIndex()) const + { + return _list.count(); + } - return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; - } + int columnCount(const QModelIndex &/*parent*/) const + { + return eColumnCount; + } - bool setData(const QModelIndex &index, const QVariant &value, int role); - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - bool insertRows(int position, int rows, const QModelIndex &index); - bool removeRows(int position, int rows, const QModelIndex &index); + Qt::ItemFlags flags(const QModelIndex &index) const + { + if (!index.isValid()) + return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; + } + QStringList mimeTypes() const; + Qt::DropActions supportedDropActions() const; + bool dropMimeData( const QMimeData * data, Qt::DropAction action, int row, + int column, const QModelIndex& parent); + QMimeData* mimeData(const QModelIndexList &indexes) const; + + + bool setData(const QModelIndex &index, const QVariant &value, int role); + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + bool insertRows(int position, int rows, const QModelIndex &index); + bool removeRows(int position, int rows, const QModelIndex &index); + void entryAdded(NotificationItem* item); + +signals: + void dragRows(int position, int count); private slots: - void entryUpdated(int offset); - void entryAdded(int position); + void entryUpdated(int offset); + void dropRows(int position, int count) const; + private: - QList *_list; - QStringList headerStrings; + mutable QList& _list; + QStringList _headerStrings; }; - #endif // NOTIFYTABLEMODEL_H