Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@0: 
Chris@0: /*
Chris@52:     Sonic Visualiser
Chris@52:     An audio file viewer and annotation editor.
Chris@52:     Centre for Digital Music, Queen Mary, University of London.
Chris@202:     This file copyright 2006 Chris Cannam and QMUL.
Chris@0:     
Chris@52:     This program is free software; you can redistribute it and/or
Chris@52:     modify it under the terms of the GNU General Public License as
Chris@52:     published by the Free Software Foundation; either version 2 of the
Chris@52:     License, or (at your option) any later version.  See the file
Chris@52:     COPYING included with this distribution for more information.
Chris@0: */
Chris@0: 
Chris@0: #include "PropertyContainer.h"
Chris@199: #include "RangeMapper.h"
Chris@199: #include "UnitDatabase.h"
Chris@46: 
Chris@46: #include <iostream>
Chris@0: 
Chris@0: PropertyContainer::PropertyList
Chris@0: PropertyContainer::getProperties() const
Chris@0: {
Chris@0:     return PropertyList();
Chris@0: }
Chris@0: 
Chris@0: PropertyContainer::PropertyType
Chris@0: PropertyContainer::getPropertyType(const PropertyName &) const
Chris@0: {
Chris@0:     return InvalidProperty;
Chris@0: }
Chris@0: 
Chris@0: QString
Chris@340: PropertyContainer::getPropertyIconName(const PropertyName &) const
Chris@340: {
Chris@340:     return QString();
Chris@340: }
Chris@340: 
Chris@340: QString
Chris@0: PropertyContainer::getPropertyGroupName(const PropertyName &) const
Chris@0: {
Chris@0:     return QString();
Chris@0: }
Chris@0: 
Chris@0: int
Chris@245: PropertyContainer::getPropertyRangeAndValue(const PropertyName &,
Chris@245:                                             int *min, int *max, int *deflt) const
Chris@0: {
Chris@0:     if (min) *min = 0;
Chris@0:     if (max) *max = 0;
Chris@245:     if (deflt) *deflt = 0;
Chris@0:     return 0;
Chris@0: }
Chris@0: 
Chris@0: QString
Chris@928: PropertyContainer::getPropertyValueLabel(const PropertyName &, int) const
Chris@0: {
Chris@0:     return QString();
Chris@0: }
Chris@0: 
Chris@984: QString
Chris@984: PropertyContainer::getPropertyValueIconName(const PropertyName &, int) const
Chris@984: {
Chris@984:     return QString();
Chris@984: }
Chris@984: 
Chris@190: RangeMapper *
Chris@190: PropertyContainer::getNewPropertyRangeMapper(const PropertyName &) const
Chris@190: {
Chris@190:     return 0;
Chris@190: }
Chris@190: 
Chris@0: void
Chris@46: PropertyContainer::setProperty(const PropertyName &name, int) 
Chris@46: {
Chris@843:     cerr << "WARNING: PropertyContainer[" << getPropertyContainerName() << "]::setProperty(" << name << "): no implementation in subclass!" << endl;
Chris@46: }
Chris@46: 
Chris@387: Command *
Chris@387: PropertyContainer::getSetPropertyCommand(const PropertyName &name, int value)
Chris@46: {
Chris@245:     int currentValue = getPropertyRangeAndValue(name, 0, 0, 0);
Chris@387:     if (value == currentValue) return 0;
Chris@387:     return new SetPropertyCommand(this, name, value);
Chris@46: }
Chris@199:  
Chris@199: void
Chris@528: PropertyContainer::setPropertyFuzzy(QString nameString, QString valueString)
Chris@199: {
Chris@199:     PropertyName name;
Chris@199:     int value;
Chris@199:     if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843:         cerr << "WARNING: PropertyContainer::setProperty(\""
Chris@686:                   << nameString << "\", \""
Chris@844:                   << valueString
Chris@843:                   << "\"): Name and value conversion failed" << endl;
Chris@199:         return;
Chris@199:     }
Chris@199:     setProperty(name, value);
Chris@199: }
Chris@199:  
Chris@387: Command *
Chris@387: PropertyContainer::getSetPropertyCommand(QString nameString, QString valueString)
Chris@199: {
Chris@199:     PropertyName name;
Chris@199:     int value;
Chris@199:     if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843:         cerr << "WARNING: PropertyContainer::getSetPropertyCommand(\""
Chris@686:                   << nameString << "\", \""
Chris@844:                   << valueString
Chris@843:                   << "\"): Name and value conversion failed" << endl;
Chris@387:         return 0;
Chris@199:     }
Chris@387:     return getSetPropertyCommand(name, value);
Chris@199: }
Chris@199: 
Chris@199: bool
Chris@199: PropertyContainer::convertPropertyStrings(QString nameString, QString valueString,
Chris@199:                                           PropertyName &name, int &value)
Chris@199: {
Chris@199:     PropertyList pl = getProperties();
Chris@199: 
Chris@199:     QString adjusted = nameString.trimmed();
Chris@199:     adjusted.replace('_', ' ');
Chris@199:     adjusted.replace('-', ' ');
Chris@199:     
Chris@199:     name = "";
Chris@199: 
Chris@199:     for (PropertyList::iterator pli = pl.begin(); pli != pl.end(); ++pli) {
Chris@199: 
Chris@199:         QString label = getPropertyLabel(*pli);
Chris@199: 
Chris@199:         if (label != "" && (nameString == label || adjusted == label)) {
Chris@199:             name = *pli;
Chris@199:             break;
Chris@199:         } else if (nameString == *pli) {
Chris@199:             name = *pli;
Chris@199:             break;
Chris@199:         }
Chris@199:     }
Chris@199: 
Chris@199:     if (name == "") {
Chris@843:         cerr << "PropertyContainer::convertPropertyStrings: Unable to match name string \"" << nameString << "\"" << endl;
Chris@199:         return false;
Chris@199:     }
Chris@199: 
Chris@199:     value = 0;
Chris@199:     bool success = false;
Chris@199:     
Chris@199:     bool isDouble = false;
Chris@199:     double dval = valueString.toDouble(&isDouble);
Chris@199: 
Chris@199:     switch (getPropertyType(name)) {
Chris@199: 
Chris@199:     case ToggleProperty:
Chris@199:         if (valueString == tr("yes") || 
Chris@199:             valueString == tr("on") ||
Chris@199:             valueString == tr("true")) {
Chris@199:             value = 1; success = true;
Chris@199:         } else if (valueString == tr("no") ||
Chris@199:                    valueString == tr("off") ||
Chris@199:                    valueString == tr("false")) {
Chris@199:             value = 0; success = true;
Chris@199:         }
Chris@199:         break;
Chris@199: 
Chris@199:     case RangeProperty:
Chris@199:         if (isDouble) {
Chris@199:             RangeMapper *mapper = getNewPropertyRangeMapper(name);
Chris@199:             if (mapper) {
Chris@199:                 value = mapper->getPositionForValue(dval);
Chris@199:                 delete mapper;
Chris@199:                 success = true;
Chris@199:             }
Chris@199:         }
Chris@199:         break;
Chris@199: 
Chris@199:     case ValueProperty:
Chris@387:     case ColourProperty:
Chris@1331:     case ColourMapProperty:
Chris@199:     {
Chris@199:         int min, max;
Chris@245:         getPropertyRangeAndValue(name, &min, &max, 0);
Chris@199:         for (int i = min; i <= max; ++i) {
Chris@199:             if (valueString == getPropertyValueLabel(name, i)) {
Chris@199:                 value = i;
Chris@199:                 success = true;
Chris@199:                 break;
Chris@199:             }
Chris@199:         }
Chris@199:         break;
Chris@199:     }
Chris@199:         
Chris@199:     case UnitsProperty:
Chris@199:         value = UnitDatabase::getInstance()->getUnitId(valueString, false);
Chris@199:         if (value >= 0) success = true;
Chris@199:         else value = 0;
Chris@199:         break;
Chris@199: 
Chris@199:     case InvalidProperty:
Chris@690:         SVDEBUG << "PropertyContainer::convertPropertyStrings: Invalid property name \"" << name << "\"" << endl;
Chris@199:         return false;
Chris@199:     }
Chris@199: 
Chris@199:     if (success) return true;
Chris@199: 
Chris@199:     int min, max;
Chris@245:     getPropertyRangeAndValue(name, &min, &max, 0);
Chris@199:     
Chris@199:     bool ok = false;
Chris@199:     int i = valueString.toInt(&ok);
Chris@199:     if (!ok) {
Chris@843:         cerr << "PropertyContainer::convertPropertyStrings: Unable to parse value string \"" << valueString << "\"" << endl;
Chris@199:         return false;
Chris@199:     } else if (i < min || i > max) {
Chris@690:         SVDEBUG << "PropertyContainer::convertPropertyStrings: Property value \"" << i << "\" outside valid range " << min << " to " << max << endl;
Chris@199:         return false;
Chris@199:     }
Chris@199: 
Chris@199:     value = i;
Chris@199:     return true;
Chris@199: }
Chris@46: 
Chris@46: PropertyContainer::SetPropertyCommand::SetPropertyCommand(PropertyContainer *pc,
Chris@46: 							  const PropertyName &pn,
Chris@46: 							  int value) :
Chris@46:     m_pc(pc),
Chris@46:     m_pn(pn),
Chris@46:     m_value(value),
Chris@46:     m_oldValue(0)
Chris@0: {
Chris@0: }
Chris@0: 
Chris@46: void
Chris@46: PropertyContainer::SetPropertyCommand::execute()
Chris@46: {
Chris@245:     m_oldValue = m_pc->getPropertyRangeAndValue(m_pn, 0, 0, 0);
Chris@46:     m_pc->setProperty(m_pn, m_value);
Chris@46: }
Chris@46: 
Chris@46: void
Chris@46: PropertyContainer::SetPropertyCommand::unexecute() 
Chris@46: {
Chris@46:     m_pc->setProperty(m_pn, m_oldValue);
Chris@46: }
Chris@46: 
Chris@46: QString
Chris@46: PropertyContainer::SetPropertyCommand::getName() const
Chris@46: {
Chris@247:     return tr("Set %1 Property").arg(m_pn);
Chris@46: }
Chris@46: