Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/configobject.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           configobject.cpp  -  description
00003                              -------------------
00004     begin                : Thu Jun 6 2002
00005     copyright            : (C) 2002 by Tue & Ken Haste Andersen
00006     email                : haste@diku.dk
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 *                                                                         *
00011 *   This program is free software; you can redistribute it and/or modify  *
00012 *   it under the terms of the GNU General Public License as published by  *
00013 *   the Free Software Foundation; either version 2 of the License, or     *
00014 *   (at your option) any later version.                                   *
00015 *                                                                         *
00016 ***************************************************************************/
00017 #include <qapplication.h>
00018 #include "configobject.h"
00019 #include <qdir.h>
00020 #include <QtDebug>
00021 #include "widget/wwidget.h"
00022 
00023 #ifdef __C_METRICS__
00024 #include "cmetrics.h"
00025 #endif
00026 
00027 #ifdef __WINDOWS__
00028 #include <windows.h>
00029 #endif
00030 
00031 #ifdef __APPLE__
00032 #include <CoreFoundation/CoreFoundation.h>
00033 #endif
00034 
00035 #include <qiodevice.h>
00036 #include <QTextStream>
00037 #include <math.h>
00038 
00039 ConfigKey::ConfigKey()
00040 {
00041 }
00042 
00043 ConfigKey::ConfigKey(QString g, QString i)
00044 {
00045     group = g;
00046     item = i;
00047 }
00048 
00049 // static
00050 ConfigKey ConfigKey::parseCommaSeparated(QString key) {
00051     ConfigKey configKey;
00052     int comma = key.indexOf(",");
00053     configKey.group = key.left(comma);
00054     configKey.item = key.mid(comma+1);
00055     return configKey;
00056 }
00057 
00058 ConfigValue::ConfigValue()
00059 {
00060 }
00061 
00062 ConfigValue::ConfigValue(QString _value)
00063 {
00064     value = _value;
00065 }
00066 
00067 ConfigValue::ConfigValue(int _value)
00068 {
00069     value = QString::number(_value);
00070 }
00071 
00072 void ConfigValue::valCopy(const ConfigValue _value)
00073 {
00074     value = _value.value;
00075 }
00076 
00077 
00078 ConfigValueKbd::ConfigValueKbd()
00079 {
00080 }
00081 
00082 ConfigValueKbd::ConfigValueKbd(QString _value) : ConfigValue(_value)
00083 {
00084     QString key;
00085 
00086     QTextStream(&_value) >> key;
00087     m_qKey = QKeySequence(key);
00088 }
00089 
00090 ConfigValueKbd::ConfigValueKbd(QKeySequence key)
00091 {
00092     m_qKey = key;
00093     QTextStream(&value) << m_qKey.toString();
00094 //          qDebug() << "value" << value;
00095 }
00096 
00097 void ConfigValueKbd::valCopy(const ConfigValueKbd v)
00098 {
00099     m_qKey = v.m_qKey;
00100     QTextStream(&value) << m_qKey.toString();
00101 }
00102 
00103 bool operator==(const ConfigValue & s1, const ConfigValue & s2)
00104 {
00105     return (s1.value.toUpper() == s2.value.toUpper());
00106 }
00107 
00108 bool operator==(const ConfigValueKbd & s1, const ConfigValueKbd & s2)
00109 {
00110     return (s1.value.toUpper() == s2.value.toUpper());
00111 }
00112 
00113 template <class ValueType> ConfigObject<ValueType>::ConfigObject(QString file)
00114 {
00115     reopen(file);
00116 }
00117 
00118 template <class ValueType> ConfigObject<ValueType>::~ConfigObject()
00119 {
00120     while (list.size() > 0) {
00121         ConfigOption<ValueType>* pConfigOption = list.takeLast();
00122         delete pConfigOption;
00123     }
00124 }
00125 
00126 template <class ValueType>
00127 ConfigOption<ValueType> *ConfigObject<ValueType>::set(ConfigKey k, ValueType v)
00128 {
00129     // Search for key in list, and set value if found
00130     QListIterator<ConfigOption<ValueType>* > iterator(list);
00131     ConfigOption<ValueType>* it;
00132     while (iterator.hasNext())
00133     {
00134         it = iterator.next();
00135 //         if (QString::compare(it->val->value, v.value, Qt::CaseInsensitive) == 0)
00136         if (it->key->group == k.group && it->key->item == k.item)
00137         {
00138             //qDebug() << "set found." << group << "," << item;
00139             //cout << "1: " << v.value << "\n";
00140             //qDebug() << "configobject " << it->val;
00141             it->val->valCopy(v); // Should be done smarter using object copying
00142             //qDebug() << "configobject " << it->val;
00143             //cout << "2: " << it->val->value << "\n";
00144             return it;
00145         }
00146     }
00147 
00148     // If key is not found, insert it into the list of config objects
00149     ConfigKey * key = new ConfigKey(k.group, k.item);
00150     it = new ConfigOption<ValueType>(key, new ValueType(v));
00151     //qDebug() << "new configobject " << it->val;
00152     list.append(it);
00153     return it;
00154 }
00155 
00156 template <class ValueType>
00157 ConfigOption<ValueType> *ConfigObject<ValueType>::get(ConfigKey k)
00158 {
00159     QListIterator<ConfigOption<ValueType>* > iterator(list);
00160     ConfigOption<ValueType>* it;
00161     while (iterator.hasNext())
00162     {
00163         it = iterator.next();
00164         //qDebug() << it->key->group << k->group << it->key->item << k->item;
00165         if (it->key->group == k.group && it->key->item == k.item)
00166         {
00167             //cout << it->key->group << ":" << it->key->item << ", val: " << it->val->value << "\n";
00168             return it;
00169         }
00170     }
00171     // If key is not found, insert into list with null values
00172     ConfigKey * key = new ConfigKey(k.group, k.item);
00173     it = new ConfigOption<ValueType>(key, new ValueType(""));
00174     list.append(it);
00175     return it;
00176 }
00177 
00178 template <class ValueType>
00179 ConfigKey *ConfigObject<ValueType>::get(ValueType v)
00180 {
00181     QListIterator<ConfigOption<ValueType>* > iterator(list);
00182     ConfigOption<ValueType>* it;
00183     while (iterator.hasNext())
00184     {
00185         it = iterator.next();
00186         if (QString::compare(it->val->value, v.value, Qt::CaseInsensitive) == 0){
00187             //qDebug() << "ConfigObject #534: QString::compare match for " << it->key->group << it->key->item;
00188             return it->key;
00189         }
00190         if (((ValueType)*it->val) == ((ValueType)v))
00191         {
00192             //qDebug() << "ConfigObject: match" << it->val->value.toUpper() << "with" << v.value.toUpper();
00193             return it->key;
00194         }
00195 
00196         if (it == list.last()) {
00197             //qDebug() << "ConfigObject: last match attempted" << it->val->value.toUpper() << "with" << v.value.toUpper();
00198         }
00199     }
00200     //qDebug() << "No match for ConfigObject:" << v.value;
00201     return 0;
00202 }
00203 
00204 template <class ValueType>
00205 QString ConfigObject<ValueType>::getValueString(ConfigKey k)
00206 {
00207     return get(k)->val->value;
00208 }
00209 
00210 template <class ValueType> bool ConfigObject<ValueType>::Parse()
00211 {
00212     // Open file for reading
00213     QFile configfile(filename);
00214     if (filename.length()<1 || !configfile.open(QIODevice::ReadOnly))
00215     {
00216         qDebug() << "Could not read" << filename;
00217         return false;
00218     }
00219     else
00220     {
00221         // Parse the file
00222         int group = 0;
00223         QString groupStr, line;
00224         QTextStream text(&configfile);
00225 
00226         while (!text.atEnd())
00227         {
00228             line = text.readLine().trimmed();
00229 
00230             if (line.length() != 0)
00231                         {
00232                 if (line.startsWith("[") && line.endsWith("]"))
00233                 {
00234                     group++;
00235                     groupStr = line;
00236                     //qDebug() << "Group :" << groupStr;
00237                 }
00238                 else if (group>0)
00239                 {
00240                     QString key;
00241                     QTextStream(&line) >> key;
00242                     QString val = line.right(line.length() - key.length()); // finds the value string
00243                     val = val.trimmed();
00244                     //qDebug() << "control:" << key << "value:" << val;
00245                     ConfigKey k(groupStr, key);
00246                     ValueType m(val);
00247                     set(k, m);
00248                 }
00249                         }
00250         }
00251         configfile.close();
00252     }
00253     return true;
00254 }
00255 
00256 
00257 template <class ValueType> void ConfigObject<ValueType>::clear()
00258 {
00259     //Delete the pointers, because that's what we did before we
00260     //purged Mixxx of Qt3 code. -- Albert, June 18th 2010 (at 30,000 ft)
00261     for (int i = 0; i < list.count(); i++)
00262         delete list[i];
00263 
00264     // This shouldn't be done, since objects might have references to
00265     // members of list. Instead all member values should be set to some
00266     // null value.
00267     list.clear();
00268 
00269 }
00270 
00271 template <class ValueType> void ConfigObject<ValueType>::reopen(QString file)
00272 {
00273     // First try to open the config file placed in the users .mixxx directory.
00274     // If that fails, try the system wide CONFIG_PATH.
00275 
00276     filename = file;
00277     Parse();
00278 }
00279 
00280 template <class ValueType> void ConfigObject<ValueType>::Save()
00281 {
00282     QFile file(filename);
00283     if (!QDir(QFileInfo(file).absolutePath()).exists()) {
00284         QDir().mkpath(QFileInfo(file).absolutePath());
00285     }
00286     if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
00287     {
00288         qDebug() << "Could not write file" << filename << ", don't worry.";
00289         return;
00290     }
00291     else
00292     {
00293         QTextStream stream(&file);
00294         QString grp = "";
00295 
00296         QListIterator<ConfigOption<ValueType>* > iterator(list);
00297         ConfigOption<ValueType>* it;
00298         while (iterator.hasNext())
00299         {
00300             it = iterator.next();
00301 //            qDebug() << "group:" << it->key->group << "item" << it->key->item << "val" << it->val->value;
00302             if (it->key->group != grp)
00303             {
00304                 grp = it->key->group;
00305                 stream << "\n" << it->key->group << "\n";
00306             }
00307             stream << it->key->item << " " << it->val->value << "\n";
00308         }
00309         file.close();
00310         if (file.error()!=QFile::NoError) //could be better... should actually say what the error was..
00311           qDebug() << "Error while writing configuration file:" << file.errorString();
00312     }
00313 }
00314 
00315 template <class ValueType>
00316 QString ConfigObject<ValueType>::getConfigPath()
00317 {
00318     //
00319     // Find the config path, path where midi configuration files, skins etc. are stored.
00320     // On Unix the search order is whats listed in mixxx.cfg, then UNIX_SHARE_PATH
00321     // On Windows it is always (and only) app dir.
00322     // On OS X it is the current directory and then the Resources/ dir in the app bundle
00323     //
00324     QString qConfigPath; // TODO: this only changes once (on first load) during a run should make this a singleton.
00325 
00326     // Try to read in the resource directory from the command line
00327     QStringList commandLineArgs = QApplication::arguments();
00328     int resourcePath = commandLineArgs.indexOf("--resourcePath");
00329     if (resourcePath!=-1 && resourcePath + 1 < commandLineArgs.size()) {
00330         qDebug() << "Setting qConfigPath from location in resourcePath commandline arg:" << commandLineArgs.at(resourcePath+1);
00331         qConfigPath = commandLineArgs.at(resourcePath+1);
00332     }
00333     if (qConfigPath.isNull() || qConfigPath.isEmpty()) {
00334 #ifdef __UNIX__
00335     // On Linux, check if the path is stored in the configuration database.
00336     if (getValueString(ConfigKey("[Config]","Path")).length()>0 && QDir(getValueString(ConfigKey("[Config]","Path"))).exists())
00337         qConfigPath = getValueString(ConfigKey("[Config]","Path"));
00338     else
00339     {
00340         // Set the path according to the compile time define, UNIX_SHARE_PATH
00341         qConfigPath = UNIX_SHARE_PATH;
00342     }
00343 #endif
00344 #ifdef __WINDOWS__
00345     // On Windows, set the config dir relative to the application dir
00346     qConfigPath = QCoreApplication::applicationDirPath();
00347 #endif
00348 #ifdef __APPLE__
00349     /*
00350     // Set the path relative to the bundle directory
00351     CFURLRef pluginRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
00352     CFStringRef macPath = CFURLCopyFileSystemPath(pluginRef, kCFURLPOSIXPathStyle);
00353     char utf8path[256];
00354     //Attempt to decode obtain the macPath string as UTF-8
00355     if (CFStringGetCString(macPath, utf8path, sizeof(utf8path), kCFStringEncodingUTF8))
00356     {
00357         qConfigPath.fromUtf8(utf8path);
00358     }
00359     else {
00360         //Fallback on the "system encoding"... (this is just our old code, which probably doesn't make any sense
00361          //since it plays roullette with the type of text encoding)
00362         qConfigPath = CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding());
00363     }
00364     qConfigPath.append("/Contents/Resources/"); //XXX this should really use QDir, this entire function should
00365     */
00366     QString mixxxPath = QCoreApplication::applicationDirPath();
00367     if (mixxxPath.endsWith("osx_build"))   //Development configuration
00368         qConfigPath = mixxxPath + "/../res";
00369     else //Release configuraton
00370             qConfigPath = mixxxPath + "/../Resources";
00371 #endif
00372     }
00373         if (qConfigPath.length() == 0) qCritical() << "qConfigPath is empty, this can not be so -- did our developer forget to define one of __UNIX__, __WINDOWS__, __APPLE__??";
00374     // If the directory does not end with a "/", add one
00375     if (!qConfigPath.endsWith("/"))
00376         qConfigPath.append("/");
00377 
00378     return qConfigPath;
00379 }
00380 
00381 
00382 template <class ValueType> ConfigObject<ValueType>::ConfigObject(QDomNode node) {
00383 
00384     if (!node.isNull() && node.isElement()) {
00385         QDomNode ctrl = node.firstChild();
00386 
00387         while (!ctrl.isNull()) {
00388             if(ctrl.nodeName() == "control") {
00389                 QString group = WWidget::selectNodeQString(ctrl, "group");
00390                 QString key = WWidget::selectNodeQString(ctrl, "key");
00391                 ConfigKey k(group, key);
00392                 ValueType m(ctrl);
00393                 set(k, m);
00394             }
00395             ctrl = ctrl.nextSibling();
00396         }
00397     }
00398 }
00399 
00400 
00401 template class ConfigObject<ConfigValue>;
00402 template class ConfigObject<ConfigValueKbd>;
00403 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines