diff --git a/src/configobject.cpp b/src/configobject.cpp index 78d0ea57d0c5..433dbbe1c153 100644 --- a/src/configobject.cpp +++ b/src/configobject.cpp @@ -29,214 +29,115 @@ ConfigKey::ConfigKey() { } -ConfigKey::ConfigKey(const QString& g, const QString& i) - : group(g), - item(i) { +ConfigKey::ConfigKey(const ConfigKey& key) + : group(key.group), + item(key.item) { } -ConfigKey::ConfigKey(const char* g, const char* i) +ConfigKey::ConfigKey(const QString& g, const QString& i) : group(g), item(i) { } // static ConfigKey ConfigKey::parseCommaSeparated(QString key) { - ConfigKey configKey; int comma = key.indexOf(","); - configKey.group = key.left(comma); - configKey.item = key.mid(comma+1); + ConfigKey configKey(key.left(comma), key.mid(comma + 1)); return configKey; } -ConfigValue::ConfigValue() -{ +ConfigValue::ConfigValue() { } -ConfigValue::ConfigValue(QString _value) -{ - value = _value; +ConfigValue::ConfigValue(QString stValue) + : value(stValue) { } -ConfigValue::ConfigValue(int _value) -{ - value = QString::number(_value); +ConfigValue::ConfigValue(int iValue) + : value(QString::number(iValue)) { } -void ConfigValue::valCopy(const ConfigValue& _value) -{ - value = _value.value; +void ConfigValue::valCopy(const ConfigValue& configValue) { + value = configValue.value; } -ConfigValueKbd::ConfigValueKbd() -{ +ConfigValueKbd::ConfigValueKbd() { } -ConfigValueKbd::ConfigValueKbd(QString _value) : ConfigValue(_value) -{ - QString key; - - QTextStream(&_value) >> key; - m_qKey = QKeySequence(key); +ConfigValueKbd::ConfigValueKbd(QString value) + : ConfigValue(value) { + m_qKey = QKeySequence(value); } -ConfigValueKbd::ConfigValueKbd(QKeySequence key) -{ +ConfigValueKbd::ConfigValueKbd(QKeySequence key) { m_qKey = key; QTextStream(&value) << m_qKey.toString(); -// qDebug() << "value" << value; + // qDebug() << "value" << value; } -void ConfigValueKbd::valCopy(const ConfigValueKbd& v) -{ +void ConfigValueKbd::valCopy(const ConfigValueKbd& v) { m_qKey = v.m_qKey; QTextStream(&value) << m_qKey.toString(); } -bool operator==(const ConfigValue& s1, const ConfigValue& s2) -{ +bool operator==(const ConfigValue& s1, const ConfigValue& s2) { return (s1.value.toUpper() == s2.value.toUpper()); } -bool operator==(const ConfigValueKbd& s1, const ConfigValueKbd& s2) -{ - return (s1.value.toUpper() == s2.value.toUpper()); +bool operator==(const ConfigValueKbd& s1, const ConfigValueKbd& s2) { + //qDebug() << s1.m_qKey << "==" << s2.m_qKey; + return (s1.m_qKey == s2.m_qKey); } -template ConfigObject::ConfigObject(QString file) -{ +template ConfigObject::ConfigObject(QString file) { reopen(file); } -template ConfigObject::~ConfigObject() -{ - while (m_list.size() > 0) { - ConfigOption* pConfigOption = m_list.takeLast(); - delete pConfigOption; - } -} - -template -ConfigOption *ConfigObject::set(ConfigKey k, ValueType v) -{ - // Search for key in list, and set value if found - QListIterator* > iterator(m_list); - ConfigOption* it; - while (iterator.hasNext()) - { - it = iterator.next(); -// if (QString::compare(it->val->value, v.value, Qt::CaseInsensitive) == 0) - if (it->key->group == k.group && it->key->item == k.item) - { - //qDebug() << "set found." << group << "," << item; - //cout << "1: " << v.value << "\n"; - //qDebug() << "configobject " << it->val; - it->val->valCopy(v); // Should be done smarter using object copying - //qDebug() << "configobject " << it->val; - //cout << "2: " << it->val->value << "\n"; - return it; - } - } - - // If key is not found, insert it into the list of config objects - ConfigKey * key = new ConfigKey(k.group, k.item); - it = new ConfigOption(key, new ValueType(v)); - //qDebug() << "new configobject " << it->val; - m_list.append(it); - return it; +template ConfigObject::~ConfigObject() { } template -ConfigOption *ConfigObject::get(ConfigKey k) -{ - QListIterator* > iterator(m_list); - ConfigOption* it; - while (iterator.hasNext()) - { - it = iterator.next(); - //qDebug() << it->key->group << k->group << it->key->item << k->item; - if (it->key->group == k.group && it->key->item == k.item) - { - //cout << it->key->group << ":" << it->key->item << ", val: " << it->val->value << "\n"; - return it; - } - } - // If key is not found, insert into list with null values - ConfigKey * key = new ConfigKey(k.group, k.item); - it = new ConfigOption(key, new ValueType("")); - m_list.append(it); - return it; +void ConfigObject::set(const ConfigKey& k, ValueType v) { + QWriteLocker lock(&m_valuesLock); + m_values.insert(k, v); } template -bool ConfigObject::exists(ConfigKey k) -{ - QListIterator* > iterator(m_list); - ConfigOption* it; - while (iterator.hasNext()) - { - it = iterator.next(); - if (it->key->group == k.group && it->key->item == k.item) - { - return true; - } - } - return false; +ValueType ConfigObject::get(const ConfigKey& k) const { + QReadLocker lock(&m_valuesLock); + return m_values.value(k); } template -ConfigKey *ConfigObject::get(ValueType v) -{ - QListIterator* > iterator(m_list); - ConfigOption* it; - while (iterator.hasNext()) - { - it = iterator.next(); - if (QString::compare(it->val->value, v.value, Qt::CaseInsensitive) == 0) { - //qDebug() << "ConfigObject #534: QString::compare match for " << it->key->group << it->key->item; - return it->key; - } - if (((ValueType)*it->val) == ((ValueType)v)) - { - //qDebug() << "ConfigObject: match" << it->val->value.toUpper() << "with" << v.value.toUpper(); - return it->key; - } - - if (it == m_list.last()) { - //qDebug() << "ConfigObject: last match attempted" << it->val->value.toUpper() << "with" << v.value.toUpper(); - } - } - //qDebug() << "No match for ConfigObject:" << v.value; - return 0; +bool ConfigObject::exists(const ConfigKey& k) const { + QReadLocker lock(&m_valuesLock); + return m_values.contains(k); } template -QString ConfigObject::getValueString(ConfigKey k) -{ - return get(k)->val->value; +QString ConfigObject::getValueString(const ConfigKey& k) const { + ValueType v = get(k); + return v.value; } template -QString ConfigObject::getValueString(ConfigKey k, const QString& default_string) -{ - QString ret = get(k)->val->value; +QString ConfigObject::getValueString(const ConfigKey& k, + const QString& default_string) const { + QString ret = getValueString(k); if (ret.isEmpty()) { return default_string; } return ret; } -template bool ConfigObject::Parse() -{ +template bool ConfigObject::parse() { // Open file for reading QFile configfile(m_filename); - if (m_filename.length()<1 || !configfile.open(QIODevice::ReadOnly)) - { + if (m_filename.length() < 1 || !configfile.open(QIODevice::ReadOnly)) { qDebug() << "ConfigObject: Could not read" << m_filename; return false; - } - else - { + } else { //qDebug() << "ConfigObject: Parse" << m_filename; // Parse the file int group = 0; @@ -244,20 +145,14 @@ template bool ConfigObject::Parse() QTextStream text(&configfile); text.setCodec("UTF-8"); - while (!text.atEnd()) - { + while (!text.atEnd()) { line = text.readLine().trimmed(); - - if (line.length() != 0) - { - if (line.startsWith("[") && line.endsWith("]")) - { + if (line.length() != 0) { + if (line.startsWith("[") && line.endsWith("]")) { group++; groupStr = line; //qDebug() << "Group :" << groupStr; - } - else if (group>0) - { + } else if (group > 0) { QString key; QTextStream(&line) >> key; QString val = line.right(line.length() - key.length()); // finds the value string @@ -274,60 +169,39 @@ template bool ConfigObject::Parse() return true; } -template void ConfigObject::clear() -{ - //Delete the pointers, because that's what we did before we - //purged Mixxx of Qt3 code. -- Albert, June 18th 2010 (at 30,000 ft) - for (int i = 0; i < m_list.count(); i++) - delete m_list[i]; - - // This shouldn't be done, since objects might have references to - // members of list. Instead all member values should be set to some - // null value. - m_list.clear(); - -} - -template void ConfigObject::reopen(QString file) -{ +template void ConfigObject::reopen(QString file) { m_filename = file; - Parse(); + parse(); } -template void ConfigObject::Save() -{ +template void ConfigObject::Save() { + QReadLocker lock(&m_valuesLock); // we only read the m_values here. QFile file(m_filename); if (!QDir(QFileInfo(file).absolutePath()).exists()) { QDir().mkpath(QFileInfo(file).absolutePath()); } - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) - { + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Could not write file" << m_filename << ", don't worry."; return; - } - else - { + } else { QTextStream stream(&file); stream.setCodec("UTF-8"); QString grp = ""; - QListIterator* > iterator(m_list); - ConfigOption* it; - while (iterator.hasNext()) - { - it = iterator.next(); -// qDebug() << "group:" << it->key->group << "item" << it->key->item << "val" << it->val->value; - if (it->key->group != grp) - { - grp = it->key->group; - stream << "\n" << it->key->group << "\n"; + typename QMap::const_iterator i; + for (i = m_values.begin(); i != m_values.end(); ++i) { + //qDebug() << "group:" << it.key().group << "item" << it.key().item << "val" << it.value()->value; + if (i.key().group != grp) { + grp = i.key().group; + stream << "\n" << grp << "\n"; } - stream << it->key->item << " " << it->val->value << "\n"; + stream << i.key().item << " " << i.value().value << "\n"; } file.close(); - if (file.error()!=QFile::NoError) //could be better... should actually say what the error was.. - qDebug() << "Error while writing configuration file:" << file.errorString(); + if (file.error()!=QFile::NoError) { //could be better... should actually say what the error was.. + qDebug() << "Error while writing configuration file:" << file.errorString(); + } } } @@ -409,18 +283,22 @@ template ConfigObject::ConfigObject(QDomNode node) } } -template QString ConfigObject::getSettingsPath() const -{ +template +QString ConfigObject::getSettingsPath() const { QFileInfo configFileInfo(m_filename); return configFileInfo.absoluteDir().absolutePath(); } -template QHash ConfigObject::toHash() const { - QHash hash; - foreach (ConfigOption* pOption, m_list) { - hash.insert(*pOption->key, *pOption->val); +template +QMultiHash ConfigObject::transpose() const { + QReadLocker lock(&m_valuesLock); + + QMultiHash transposedHash; + for (typename QMap::const_iterator it = + m_values.begin(); it != m_values.end(); ++it) { + transposedHash.insert(it.value(), it.key()); } - return hash; + return transposedHash; } template class ConfigObject; diff --git a/src/configobject.h b/src/configobject.h index 852198909678..9090b943f117 100644 --- a/src/configobject.h +++ b/src/configobject.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "util/debug.h" @@ -34,23 +35,32 @@ class ConfigKey { public: - ConfigKey(); + ConfigKey(); // is required for qMetaTypeConstructHelper() + ConfigKey(const ConfigKey& key); ConfigKey(const QString& g, const QString& i); - ConfigKey(const char* g, const char* i); static ConfigKey parseCommaSeparated(QString key); inline bool isNull() const { return group.isNull() && item.isNull(); } + // comparison function for ConfigKeys. Used by a QHash in ControlObject + inline bool operator==(const ConfigKey& other) const { + return group == other.group && item == other.item; + } + + // comparison function for ConfigKeys. Used by a QMap in ControlObject + inline bool operator<(const ConfigKey& other) const { + int groupResult = group.compare(other.group); + if (groupResult == 0) { + return item < other.item; + } + return (groupResult < 0); + } QString group, item; }; Q_DECLARE_METATYPE(ConfigKey); -// comparison function for ConfigKeys. Used by a QHash in ControlObject -inline bool operator==(const ConfigKey& c1, const ConfigKey& c2) { - return c1.group == c2.group && c1.item == c2.item; -} // stream operator function for trivial qDebug()ing of ConfigKeys inline QDebug operator<<(QDebug stream, const ConfigKey& c1) { @@ -73,17 +83,21 @@ inline uint qHash(const QKeySequence& key) { class ConfigValue { public: ConfigValue(); - ConfigValue(QString _value); - ConfigValue(int _value); + ConfigValue(QString value); + ConfigValue(int value); inline ConfigValue(QDomNode /* node */) { reportFatalErrorAndQuit("ConfigValue from QDomNode not implemented here"); } - void valCopy(const ConfigValue& _value); + void valCopy(const ConfigValue& value); QString value; friend bool operator==(const ConfigValue& s1, const ConfigValue& s2); }; +inline uint qHash(const ConfigValue& key) { + return qHash(key.value.toUpper()); +} + class ConfigValueKbd : public ConfigValue { public: ConfigValueKbd(); @@ -98,36 +112,18 @@ class ConfigValueKbd : public ConfigValue { QKeySequence m_qKey; }; -template class ConfigOption { - public: - ConfigOption() { val = NULL; key = NULL;}; - ConfigOption(ConfigKey* _key, ValueType* _val) { key = _key ; val = _val; }; - virtual ~ConfigOption() { - delete key; - delete val; - } - ValueType* val; - ConfigKey* key; -}; - template class ConfigObject { public: - ConfigKey key; - ValueType value; - ConfigOption option; - ConfigObject(QString file); ConfigObject(QDomNode node); ~ConfigObject(); - ConfigOption *set(ConfigKey, ValueType); - ConfigOption *get(ConfigKey key); - bool exists(ConfigKey key); - ConfigKey *get(ValueType v); - QString getValueString(ConfigKey k); - QString getValueString(ConfigKey k, const QString& default_string); - QHash toHash() const; - - void clear(); + void set(const ConfigKey& k, ValueType); + ValueType get(const ConfigKey& k) const; + bool exists(const ConfigKey& key) const; + QString getValueString(const ConfigKey& k) const; + QString getValueString(const ConfigKey& k, const QString& default_string) const; + QMultiHash transpose() const; + void reopen(QString file); void Save(); @@ -140,12 +136,14 @@ template class ConfigObject { QString getSettingsPath() const; protected: - QList*> m_list; + // We use QMap because we want a sorted list in mixxx.cfg + QMap m_values; + mutable QReadWriteLock m_valuesLock; QString m_filename; // Loads and parses the configuration file. Returns false if the file could // not be opened; otherwise true. - bool Parse(); + bool parse(); }; #endif diff --git a/src/mixxxkeyboard.cpp b/src/mixxxkeyboard.cpp index 422817684afa..1054c3cc9b47 100644 --- a/src/mixxxkeyboard.cpp +++ b/src/mixxxkeyboard.cpp @@ -65,11 +65,13 @@ bool MixxxKeyboard::eventFilter(QObject*, QEvent* e) { QKeySequence ks = getKeySeq(ke); if (!ks.isEmpty()) { + ConfigValueKbd ksv(ks); // Check if a shortcut is defined bool result = false; - for (QMultiHash::const_iterator it = - m_keySequenceToControlHash.find(ks); - it != m_keySequenceToControlHash.end() && it.key() == ks; ++it) { + // using const_iterator here is faster than QMultiHash::values() + for (QMultiHash::const_iterator it = + m_keySequenceToControlHash.find(ksv); + it != m_keySequenceToControlHash.end() && it.key() == ksv; ++it) { const ConfigKey& configKey = it.value(); if (configKey.group != "[KeyboardShortcuts]") { ControlObject* control = ControlObject::getControl(configKey); @@ -178,14 +180,7 @@ void MixxxKeyboard::setKeyboardConfig(ConfigObject* pKbdConfigOb // invert the mapping to create an injection from key sequence to // ConfigKey. This allows a key sequence to trigger multiple controls in // Mixxx. - QHash keyboardConfig = - pKbdConfigObject->toHash(); - - m_keySequenceToControlHash.clear(); - for (QHash::const_iterator it = - keyboardConfig.begin(); it != keyboardConfig.end(); ++it) { - m_keySequenceToControlHash.insert(it.value().m_qKey, it.key()); - } + m_keySequenceToControlHash = pKbdConfigObject->transpose(); m_pKbdConfigObject = pKbdConfigObject; } diff --git a/src/mixxxkeyboard.h b/src/mixxxkeyboard.h index f86f7b06c213..f73892e78aa1 100644 --- a/src/mixxxkeyboard.h +++ b/src/mixxxkeyboard.h @@ -62,7 +62,7 @@ class MixxxKeyboard : public QObject { // Pointer to keyboard config object ConfigObject *m_pKbdConfigObject; // Multi-hash of key sequence to - QMultiHash m_keySequenceToControlHash; + QMultiHash m_keySequenceToControlHash; }; #endif