annotate base/PropertyContainer.cpp @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents 70e172e6cc59
children
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "PropertyContainer.h"
Chris@199 17 #include "RangeMapper.h"
Chris@199 18 #include "UnitDatabase.h"
Chris@46 19
Chris@46 20 #include <iostream>
Chris@0 21
Chris@0 22 PropertyContainer::PropertyList
Chris@0 23 PropertyContainer::getProperties() const
Chris@0 24 {
Chris@0 25 return PropertyList();
Chris@0 26 }
Chris@0 27
Chris@0 28 PropertyContainer::PropertyType
Chris@0 29 PropertyContainer::getPropertyType(const PropertyName &) const
Chris@0 30 {
Chris@0 31 return InvalidProperty;
Chris@0 32 }
Chris@0 33
Chris@0 34 QString
Chris@340 35 PropertyContainer::getPropertyIconName(const PropertyName &) const
Chris@340 36 {
Chris@340 37 return QString();
Chris@340 38 }
Chris@340 39
Chris@340 40 QString
Chris@0 41 PropertyContainer::getPropertyGroupName(const PropertyName &) const
Chris@0 42 {
Chris@0 43 return QString();
Chris@0 44 }
Chris@0 45
Chris@0 46 int
Chris@245 47 PropertyContainer::getPropertyRangeAndValue(const PropertyName &,
Chris@245 48 int *min, int *max, int *deflt) const
Chris@0 49 {
Chris@0 50 if (min) *min = 0;
Chris@0 51 if (max) *max = 0;
Chris@245 52 if (deflt) *deflt = 0;
Chris@0 53 return 0;
Chris@0 54 }
Chris@0 55
Chris@0 56 QString
Chris@928 57 PropertyContainer::getPropertyValueLabel(const PropertyName &, int) const
Chris@0 58 {
Chris@0 59 return QString();
Chris@0 60 }
Chris@0 61
Chris@984 62 QString
Chris@984 63 PropertyContainer::getPropertyValueIconName(const PropertyName &, int) const
Chris@984 64 {
Chris@984 65 return QString();
Chris@984 66 }
Chris@984 67
Chris@190 68 RangeMapper *
Chris@190 69 PropertyContainer::getNewPropertyRangeMapper(const PropertyName &) const
Chris@190 70 {
Chris@1582 71 return nullptr;
Chris@190 72 }
Chris@190 73
Chris@0 74 void
Chris@46 75 PropertyContainer::setProperty(const PropertyName &name, int)
Chris@46 76 {
Chris@843 77 cerr << "WARNING: PropertyContainer[" << getPropertyContainerName() << "]::setProperty(" << name << "): no implementation in subclass!" << endl;
Chris@46 78 }
Chris@46 79
Chris@387 80 Command *
Chris@387 81 PropertyContainer::getSetPropertyCommand(const PropertyName &name, int value)
Chris@46 82 {
Chris@1582 83 int currentValue = getPropertyRangeAndValue(name, nullptr, nullptr, nullptr);
Chris@1582 84 if (value == currentValue) return nullptr;
Chris@387 85 return new SetPropertyCommand(this, name, value);
Chris@46 86 }
Chris@199 87
Chris@199 88 void
Chris@528 89 PropertyContainer::setPropertyFuzzy(QString nameString, QString valueString)
Chris@199 90 {
Chris@199 91 PropertyName name;
Chris@199 92 int value;
Chris@199 93 if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843 94 cerr << "WARNING: PropertyContainer::setProperty(\""
Chris@686 95 << nameString << "\", \""
Chris@844 96 << valueString
Chris@843 97 << "\"): Name and value conversion failed" << endl;
Chris@199 98 return;
Chris@199 99 }
Chris@199 100 setProperty(name, value);
Chris@199 101 }
Chris@199 102
Chris@387 103 Command *
Chris@387 104 PropertyContainer::getSetPropertyCommand(QString nameString, QString valueString)
Chris@199 105 {
Chris@199 106 PropertyName name;
Chris@199 107 int value;
Chris@199 108 if (!convertPropertyStrings(nameString, valueString, name, value)) {
Chris@843 109 cerr << "WARNING: PropertyContainer::getSetPropertyCommand(\""
Chris@686 110 << nameString << "\", \""
Chris@844 111 << valueString
Chris@843 112 << "\"): Name and value conversion failed" << endl;
Chris@1582 113 return nullptr;
Chris@199 114 }
Chris@387 115 return getSetPropertyCommand(name, value);
Chris@199 116 }
Chris@199 117
Chris@199 118 bool
Chris@199 119 PropertyContainer::convertPropertyStrings(QString nameString, QString valueString,
Chris@199 120 PropertyName &name, int &value)
Chris@199 121 {
Chris@199 122 PropertyList pl = getProperties();
Chris@199 123
Chris@199 124 QString adjusted = nameString.trimmed();
Chris@199 125 adjusted.replace('_', ' ');
Chris@199 126 adjusted.replace('-', ' ');
Chris@199 127
Chris@199 128 name = "";
Chris@199 129
Chris@199 130 for (PropertyList::iterator pli = pl.begin(); pli != pl.end(); ++pli) {
Chris@199 131
Chris@199 132 QString label = getPropertyLabel(*pli);
Chris@199 133
Chris@199 134 if (label != "" && (nameString == label || adjusted == label)) {
Chris@199 135 name = *pli;
Chris@199 136 break;
Chris@199 137 } else if (nameString == *pli) {
Chris@199 138 name = *pli;
Chris@199 139 break;
Chris@199 140 }
Chris@199 141 }
Chris@199 142
Chris@199 143 if (name == "") {
Chris@843 144 cerr << "PropertyContainer::convertPropertyStrings: Unable to match name string \"" << nameString << "\"" << endl;
Chris@199 145 return false;
Chris@199 146 }
Chris@199 147
Chris@199 148 value = 0;
Chris@199 149 bool success = false;
Chris@199 150
Chris@199 151 bool isDouble = false;
Chris@199 152 double dval = valueString.toDouble(&isDouble);
Chris@199 153
Chris@199 154 switch (getPropertyType(name)) {
Chris@199 155
Chris@199 156 case ToggleProperty:
Chris@199 157 if (valueString == tr("yes") ||
Chris@199 158 valueString == tr("on") ||
Chris@199 159 valueString == tr("true")) {
Chris@199 160 value = 1; success = true;
Chris@199 161 } else if (valueString == tr("no") ||
Chris@199 162 valueString == tr("off") ||
Chris@199 163 valueString == tr("false")) {
Chris@199 164 value = 0; success = true;
Chris@199 165 }
Chris@199 166 break;
Chris@199 167
Chris@199 168 case RangeProperty:
Chris@199 169 if (isDouble) {
Chris@199 170 RangeMapper *mapper = getNewPropertyRangeMapper(name);
Chris@199 171 if (mapper) {
Chris@199 172 value = mapper->getPositionForValue(dval);
Chris@199 173 delete mapper;
Chris@199 174 success = true;
Chris@199 175 }
Chris@199 176 }
Chris@199 177 break;
Chris@199 178
Chris@199 179 case ValueProperty:
Chris@387 180 case ColourProperty:
Chris@1331 181 case ColourMapProperty:
Chris@199 182 {
Chris@199 183 int min, max;
Chris@1582 184 getPropertyRangeAndValue(name, &min, &max, nullptr);
Chris@199 185 for (int i = min; i <= max; ++i) {
Chris@199 186 if (valueString == getPropertyValueLabel(name, i)) {
Chris@199 187 value = i;
Chris@199 188 success = true;
Chris@199 189 break;
Chris@199 190 }
Chris@199 191 }
Chris@199 192 break;
Chris@199 193 }
Chris@199 194
Chris@199 195 case UnitsProperty:
Chris@199 196 value = UnitDatabase::getInstance()->getUnitId(valueString, false);
Chris@199 197 if (value >= 0) success = true;
Chris@199 198 else value = 0;
Chris@199 199 break;
Chris@199 200
Chris@199 201 case InvalidProperty:
Chris@690 202 SVDEBUG << "PropertyContainer::convertPropertyStrings: Invalid property name \"" << name << "\"" << endl;
Chris@199 203 return false;
Chris@199 204 }
Chris@199 205
Chris@199 206 if (success) return true;
Chris@199 207
Chris@199 208 int min, max;
Chris@1582 209 getPropertyRangeAndValue(name, &min, &max, nullptr);
Chris@199 210
Chris@199 211 bool ok = false;
Chris@199 212 int i = valueString.toInt(&ok);
Chris@199 213 if (!ok) {
Chris@843 214 cerr << "PropertyContainer::convertPropertyStrings: Unable to parse value string \"" << valueString << "\"" << endl;
Chris@199 215 return false;
Chris@199 216 } else if (i < min || i > max) {
Chris@690 217 SVDEBUG << "PropertyContainer::convertPropertyStrings: Property value \"" << i << "\" outside valid range " << min << " to " << max << endl;
Chris@199 218 return false;
Chris@199 219 }
Chris@199 220
Chris@199 221 value = i;
Chris@199 222 return true;
Chris@199 223 }
Chris@46 224
Chris@46 225 PropertyContainer::SetPropertyCommand::SetPropertyCommand(PropertyContainer *pc,
Chris@1429 226 const PropertyName &pn,
Chris@1429 227 int value) :
Chris@46 228 m_pc(pc),
Chris@46 229 m_pn(pn),
Chris@46 230 m_value(value),
Chris@46 231 m_oldValue(0)
Chris@0 232 {
Chris@0 233 }
Chris@0 234
Chris@46 235 void
Chris@46 236 PropertyContainer::SetPropertyCommand::execute()
Chris@46 237 {
Chris@1582 238 m_oldValue = m_pc->getPropertyRangeAndValue(m_pn, nullptr, nullptr, nullptr);
Chris@46 239 m_pc->setProperty(m_pn, m_value);
Chris@46 240 }
Chris@46 241
Chris@46 242 void
Chris@46 243 PropertyContainer::SetPropertyCommand::unexecute()
Chris@46 244 {
Chris@46 245 m_pc->setProperty(m_pn, m_oldValue);
Chris@46 246 }
Chris@46 247
Chris@46 248 QString
Chris@46 249 PropertyContainer::SetPropertyCommand::getName() const
Chris@46 250 {
Chris@247 251 return tr("Set %1 Property").arg(m_pn);
Chris@46 252 }
Chris@46 253