/*************************************************************************** configobject.cpp - description ------------------- begin : Thu Jun 6 2002 copyright : (C) 2002 by Tue & Ken Haste Andersen email : haste@diku.dk ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "configobject.h" #include #include #include #include #include #include "widget/wwidget.h" #include "util/cmdlineargs.h" #include "util/xml.h" ConfigKey::ConfigKey() { } ConfigKey::ConfigKey(const QString& g, const QString& i) : group(g), item(i) { } ConfigKey::ConfigKey(const char* g, const char* 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); return configKey; } ConfigValue::ConfigValue() { } ConfigValue::ConfigValue(QString _value) { value = _value; } ConfigValue::ConfigValue(int _value) { value = QString::number(_value); } void ConfigValue::valCopy(const ConfigValue& _value) { value = _value.value; } ConfigValueKbd::ConfigValueKbd() { } ConfigValueKbd::ConfigValueKbd(QString _value) : ConfigValue(_value) { QString key; QTextStream(&_value) >> key; m_qKey = QKeySequence(key); } ConfigValueKbd::ConfigValueKbd(QKeySequence key) { m_qKey = key; QTextStream(&value) << m_qKey.toString(); // qDebug() << "value" << value; } void ConfigValueKbd::valCopy(const ConfigValueKbd& v) { m_qKey = v.m_qKey; QTextStream(&value) << m_qKey.toString(); } 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()); } 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 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; } 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; } 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; } template QString ConfigObject::getValueString(ConfigKey k) { return get(k)->val->value; } template QString ConfigObject::getValueString(ConfigKey k, const QString& default_string) { QString ret = get(k)->val->value; if (ret.isEmpty()) { return default_string; } return ret; } template bool ConfigObject::Parse() { // Open file for reading QFile configfile(m_filename); if (m_filename.length()<1 || !configfile.open(QIODevice::ReadOnly)) { qDebug() << "ConfigObject: Could not read" << m_filename; return false; } else { //qDebug() << "ConfigObject: Parse" << m_filename; // Parse the file int group = 0; QString groupStr, line; QTextStream text(&configfile); text.setCodec("UTF-8"); while (!text.atEnd()) { line = text.readLine().trimmed(); if (line.length() != 0) { if (line.startsWith("[") && line.endsWith("]")) { group++; groupStr = line; //qDebug() << "Group :" << groupStr; } else if (group>0) { QString key; QTextStream(&line) >> key; QString val = line.right(line.length() - key.length()); // finds the value string val = val.trimmed(); //qDebug() << "control:" << key << "value:" << val; ConfigKey k(groupStr, key); ValueType m(val); set(k, m); } } } configfile.close(); } 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) { m_filename = file; Parse(); } template void ConfigObject::Save() { QFile file(m_filename); if (!QDir(QFileInfo(file).absolutePath()).exists()) { QDir().mkpath(QFileInfo(file).absolutePath()); } if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Could not write file" << m_filename << ", don't worry."; return; } 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"; } stream << it->key->item << " " << it->val->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(); } } template QString ConfigObject::getResourcePath() const { // Try to read in the resource directory from the command line QString qResourcePath = CmdlineArgs::Instance().getResourcePath(); if (qResourcePath.isEmpty()) { QDir mixxxDir(QCoreApplication::applicationDirPath()); // We used to support using the mixxx.cfg's [Config],Path setting but // this causes issues if you try and use two different versions of Mixxx // on the same computer. See Bug #1392854. We start by checking if we're // running out of a build root ('res' dir exists or our path ends with // '_build') and if not then we fall back on a platform-specific method // of determining the resource path (see comments below). if (mixxxDir.cd("res")) { // We are running out of the repository root. qResourcePath = mixxxDir.absolutePath(); } else if (mixxxDir.absolutePath().endsWith("_build") && mixxxDir.cdUp() && mixxxDir.cd("res")) { // We are running out of the (lin|win|osx)XX_build folder. qResourcePath = mixxxDir.absolutePath(); } #ifdef __UNIX__ // On Linux if all of the above fail the /usr/share path is the logical // place to look. else { qResourcePath = UNIX_SHARE_PATH; } #endif #ifdef __WINDOWS__ // On Windows, set the config dir relative to the application dir if all // of the above fail. else { qResourcePath = QCoreApplication::applicationDirPath(); } #endif #ifdef __APPLE__ else if (mixxxDir.cdUp() && mixxxDir.cd("Resources")) { // Release configuraton qResourcePath = mixxxDir.absolutePath(); } else { // TODO(rryan): What should we do here? } #endif } else { //qDebug() << "Setting qResourcePath from location in resourcePath commandline arg:" << qResourcePath; } if (qResourcePath.isEmpty()) { reportCriticalErrorAndQuit("qConfigPath is empty, this can not be so -- did our developer forget to define one of __UNIX__, __WINDOWS__, __APPLE__??"); } // If the directory does not end with a "/", add one if (!qResourcePath.endsWith("/")) { qResourcePath.append("/"); } qDebug() << "Loading resources from " << qResourcePath; return qResourcePath; } template ConfigObject::ConfigObject(QDomNode node) { if (!node.isNull() && node.isElement()) { QDomNode ctrl = node.firstChild(); while (!ctrl.isNull()) { if(ctrl.nodeName() == "control") { QString group = XmlParse::selectNodeQString(ctrl, "group"); QString key = XmlParse::selectNodeQString(ctrl, "key"); ConfigKey k(group, key); ValueType m(ctrl); set(k, m); } ctrl = ctrl.nextSibling(); } } } 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); } return hash; } template class ConfigObject; template class ConfigObject;