![]() |
Mixxx
|
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