File indexing completed on 2025-01-26 04:12:19
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2013 C. Barth Netterfield * 0004 * netterfield@astro.utoronto.ca * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 ***************************************************************************/ 0012 0013 #include "sourcelist.h" 0014 #include "datasourcepluginmanager.h" 0015 0016 #include <QXmlStreamWriter> 0017 #include <QImageReader> 0018 #include <qcolor.h> 0019 #include <QFile> 0020 #include <QFileInfo> 0021 0022 0023 0024 using namespace Kst; 0025 0026 static const QString sourceListTypeString = "List of Datasources"; 0027 0028 0029 // 0030 // Vector interface 0031 // 0032 0033 class DataInterfaceSourceListVector : public DataSource::DataInterface<DataVector> 0034 { 0035 public: 0036 DataInterfaceSourceListVector(SourceListSource& d) : sourcelist(d) {} 0037 0038 // read one element 0039 int read(const QString& field, DataVector::ReadInfo& p) {return sourcelist.readField(field, p);} 0040 0041 // named elements 0042 QStringList list() const { return sourcelist._fieldList; } 0043 bool isListComplete() const { return true; } 0044 bool isValid(const QString& field) const { return sourcelist._fieldList.contains( field ); } 0045 0046 // T specific 0047 const DataVector::DataInfo dataInfo(const QString&, int frame = 0) const; 0048 void setDataInfo(const QString&, const DataVector::DataInfo&) {} 0049 0050 // meta data 0051 QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); } 0052 QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); } 0053 0054 //QMap<QString, double> metaScalars(const QString&); 0055 //QMap<QString, QString> metaStrings(const QString&); 0056 0057 SourceListSource& sourcelist; 0058 }; 0059 0060 0061 const DataVector::DataInfo DataInterfaceSourceListVector::dataInfo(const QString &field, int frame) const 0062 { 0063 Q_UNUSED(frame) 0064 if (!sourcelist._fieldList.contains(field)) 0065 return DataVector::DataInfo(); 0066 0067 return DataVector::DataInfo(sourcelist._frameCount, sourcelist.samplesPerFrame(field)); 0068 } 0069 0070 /********************** 0071 SourceListSource::Config - This class defines the config widget that will be added to the 0072 Dialog Config Button for configuring the plugin. This is only needed for special handling required 0073 by the plugin. Many plugins will not require configuration. See plugins/sampleplugin for additional 0074 details. 0075 0076 ***********************/ 0077 class SourceListSource::Config { 0078 public: 0079 Config() { 0080 } 0081 0082 void read(QSettings *cfg, const QString& fileName = QString()) { 0083 Q_UNUSED(fileName); 0084 cfg->beginGroup("Source List"); 0085 cfg->endGroup(); 0086 } 0087 0088 void save(QXmlStreamWriter& s) { 0089 Q_UNUSED(s); 0090 } 0091 0092 void load(const QDomElement& e) { 0093 Q_UNUSED(e); 0094 } 0095 }; 0096 0097 0098 /********************** 0099 SourceListSource - This class defines the main DataSource which derives from DataSource. 0100 The key functions that this class must provide is the ability to create the source, provide details about the source 0101 be able to process the data. 0102 0103 ***********************/ 0104 SourceListSource::SourceListSource(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e) 0105 : Kst::DataSource(store, cfg, filename, type), _config(0L), iv(new DataInterfaceSourceListVector(*this)) { 0106 0107 setInterface(iv); 0108 //setInterface(ix); 0109 //setInterface(is); 0110 //setInterface(im); 0111 0112 startUpdating(None); 0113 0114 _store = store; 0115 0116 _valid = false; 0117 if (!type.isEmpty() && type != "Source List") { 0118 return; 0119 } 0120 0121 _config = new SourceListSource::Config; 0122 _config->read(cfg, filename); 0123 if (!e.isNull()) { 0124 _config->load(e); 0125 } 0126 0127 if (init()) { 0128 _valid = true; 0129 } 0130 0131 registerChange(); 0132 } 0133 0134 0135 0136 SourceListSource::~SourceListSource() { 0137 } 0138 0139 0140 void SourceListSource::reset() { 0141 init(); 0142 Object::reset(); 0143 } 0144 0145 0146 // If the datasource has any predefined fields they should be populated here. 0147 bool SourceListSource::init() { 0148 _fieldList.clear(); 0149 _scalarList.clear(); 0150 _stringList.clear(); 0151 _matrixList.clear(); 0152 0153 _frameCount = 0; 0154 0155 // create the child sources, and create the list 0156 _sources.clear(); // also deletes the smart pointers... 0157 _sizeList.clear(); 0158 0159 if (!QFile::exists(_filename)) { 0160 return 0; 0161 } 0162 0163 QFile f(_filename); 0164 if (!f.open(QIODevice::ReadOnly)) { 0165 return 0; 0166 } 0167 0168 QByteArray line; 0169 0170 _frameCount = 0; 0171 0172 while (1) { 0173 line = f.readLine(5000).trimmed(); 0174 if (line.isEmpty()) { 0175 break; 0176 } 0177 // create the data source and add it to _sources 0178 DataSourcePtr ds = DataSourcePluginManager::findOrLoadSource(_store, line); 0179 if (ds) { 0180 _sources.append(ds); 0181 } 0182 } 0183 0184 if (_sources.size()>0) { 0185 _fieldList.append(_sources.at(0)->vector().list()); 0186 foreach (DataSourcePtr ds, _sources) { 0187 DataVector::DataInfo info = ds->vector().dataInfo(ds->vector().list().at(0)); 0188 _sizeList.append(info.frameCount); 0189 _frameCount += info.frameCount; 0190 } 0191 } 0192 0193 startUpdating(Timer); 0194 0195 registerChange(); 0196 return true; // false if something went wrong 0197 } 0198 0199 int SourceListSource::samplesPerFrame(const QString &field) { 0200 if (_sources.size()>0) { 0201 DataSourcePtr ds = _sources.at(0); 0202 DataVector::DataInfo info = ds->vector().dataInfo(field); 0203 return info.samplesPerFrame; 0204 } 0205 return 1; 0206 } 0207 0208 0209 // Check if the data in the from the source has updated. 0210 // For source list, we only check 0211 // -if a new file has been added 0212 // -if the last file has grown. 0213 Kst::Object::UpdateType SourceListSource::internalDataSourceUpdate() { 0214 QFile f(_filename); 0215 if (!f.open(QIODevice::ReadOnly)) { 0216 return Kst::Object::NoChange; 0217 } 0218 0219 QByteArray line; 0220 0221 // check if the list has changed 0222 for (int i = 0; i<_sources.size(); i++) { 0223 line = f.readLine(5000).trimmed(); 0224 if (line!=_sources.at(i)->fileName()) { // error: better reset 0225 qDebug() << "source list internal ds update: file list changed"; 0226 reset(); 0227 return (Kst::Object::Updated); 0228 } 0229 } 0230 line = f.readLine(5000).trimmed(); 0231 if (!line.isEmpty()) { 0232 // create the data source and add it to _sources 0233 DataSourcePtr ds = DataSourcePluginManager::findOrLoadSource(_store, line); 0234 if (ds) { 0235 _sources.append(ds); 0236 } 0237 } 0238 0239 if (_sources.size()>0) { 0240 if (_fieldList.size()<1) { 0241 _fieldList.append(_sources.at(0)->vector().list()); 0242 } 0243 _sizeList.clear(); 0244 int oldFrameCount = _frameCount; 0245 _frameCount = 0; 0246 foreach (DataSourcePtr ds, _sources) { 0247 DataVector::DataInfo info = ds->vector().dataInfo(ds->vector().list().at(0)); 0248 _sizeList.append(info.frameCount); 0249 _frameCount += info.frameCount; 0250 } 0251 if (_frameCount != oldFrameCount) { 0252 return Kst::Object::Updated; 0253 } 0254 } 0255 0256 return Kst::Object::NoChange; 0257 } 0258 0259 0260 // TODO a DataSource::DataInterface implementation as example 0261 0262 0263 0264 0265 QString SourceListSource::fileType() const { 0266 return "Source List"; 0267 } 0268 0269 0270 void SourceListSource::save(QXmlStreamWriter &streamWriter) { 0271 Kst::DataSource::save(streamWriter); 0272 } 0273 0274 // 0 1000 2000 3000 0275 // 0 1 2 3 0276 0277 int SourceListSource::readField(const QString& field, DataVector::ReadInfo& p) { 0278 int f0 = p.startingFrame; 0279 int nf = p.numberOfFrames; 0280 int i_file = 0; 0281 DataVector::ReadInfo ri; 0282 int samp_read = 0; 0283 int f_offset = 0; 0284 //if (f0<0 && nf >0) { 0285 // f0 = qMax(_frameCount - nf, 0); 0286 //} else if (nf<0 && f0>=0) { 0287 // nf = qMax(_frameCount-f0, 0); 0288 //} 0289 0290 if (f0 >= 0) { 0291 while ((f0 >= _sizeList.at(i_file)) && (i_file < _sizeList.size()-1)) { 0292 f0 -= _sizeList.at(i_file); 0293 f_offset += _sizeList.at(i_file); 0294 i_file++; 0295 } 0296 if (nf>0) { 0297 while ((nf>0) && (i_file < _sizeList.size())) { 0298 int nr = qMin(nf, _sizeList.at(i_file)-f0); 0299 ri = p; 0300 ri.startingFrame = f0; 0301 ri.numberOfFrames = nr; 0302 ri.data = p.data+samp_read; 0303 if (field == "INDEX") { 0304 for (int i=0; i<nr; i++) { 0305 ri.data[i] = i+f_offset + f0; 0306 } 0307 samp_read += nr; 0308 } else { 0309 samp_read += _sources[i_file]->vector().read(field, ri); 0310 } 0311 nf -= nr; 0312 f0 = 0; 0313 f_offset += _sizeList.at(i_file); 0314 i_file++; 0315 } 0316 } else if (nf == -1) { // read one sample 0317 ri = p; 0318 ri.startingFrame = f0; 0319 ri.numberOfFrames = nf; 0320 if (field == "INDEX") { 0321 ri.data[0] = f0 + f_offset; 0322 samp_read++; 0323 } else { 0324 samp_read += _sources[i_file]->vector().read(field, ri); 0325 } 0326 } 0327 } 0328 return samp_read; 0329 } 0330 0331 0332 // Name used to identify the plugin. Used when loading the plugin. 0333 QString SourceListPlugin::pluginName() const { return tr("Source List Reader"); } 0334 QString SourceListPlugin::pluginDescription() const { return tr("Source List Reader"); } 0335 0336 /********************** 0337 SourceListPlugin - This class defines the plugin interface to the DataSource defined by the plugin. 0338 The primary requirements of this class are to provide the necessary connections to create the object 0339 which includes providing access to the configuration widget. 0340 0341 ***********************/ 0342 0343 Kst::DataSource *SourceListPlugin::create(Kst::ObjectStore *store, 0344 QSettings *cfg, 0345 const QString &filename, 0346 const QString &type, 0347 const QDomElement &element) const { 0348 0349 return new SourceListSource(store, cfg, filename, type, element); 0350 } 0351 0352 0353 // Provides the matrix list that this dataSource can provide from the provided filename. 0354 // This function should use understands to validate the file and then open and calculate the 0355 // list of matrices. 0356 QStringList SourceListPlugin::matrixList(QSettings *cfg, 0357 const QString& filename, 0358 const QString& type, 0359 QString *typeSuggestion, 0360 bool *complete) const { 0361 0362 0363 if (typeSuggestion) { 0364 *typeSuggestion = "Source List"; 0365 } 0366 if ((!type.isEmpty() && !provides().contains(type)) || 0367 0 == understands(cfg, filename)) { 0368 if (complete) { 0369 *complete = false; 0370 } 0371 return QStringList(); 0372 } 0373 QStringList matrixList; 0374 0375 return matrixList; 0376 0377 } 0378 0379 0380 // Provides the scalar list that this dataSource can provide from the provided filename. 0381 // This function should use understands to validate the file and then open and calculate the 0382 // list of scalars if necessary. 0383 QStringList SourceListPlugin::scalarList(QSettings *cfg, 0384 const QString& filename, 0385 const QString& type, 0386 QString *typeSuggestion, 0387 bool *complete) const { 0388 0389 QStringList scalarList; 0390 0391 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0392 if (complete) { 0393 *complete = false; 0394 } 0395 return QStringList(); 0396 } 0397 0398 if (typeSuggestion) { 0399 *typeSuggestion = "Source List"; 0400 } 0401 0402 scalarList.append("FRAMES"); 0403 return scalarList; 0404 0405 } 0406 0407 0408 // Provides the string list that this dataSource can provide from the provided filename. 0409 // This function should use understands to validate the file and then open and calculate the 0410 // list of strings if necessary. 0411 QStringList SourceListPlugin::stringList(QSettings *cfg, 0412 const QString& filename, 0413 const QString& type, 0414 QString *typeSuggestion, 0415 bool *complete) const { 0416 0417 QStringList stringList; 0418 0419 if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) { 0420 if (complete) { 0421 *complete = false; 0422 } 0423 return QStringList(); 0424 } 0425 0426 if (typeSuggestion) { 0427 *typeSuggestion = "Source List"; 0428 } 0429 0430 stringList.append("FILENAME"); 0431 return stringList; 0432 0433 } 0434 0435 0436 // Provides the field list that this dataSource can provide from the provided filename. 0437 // This function should use understands to validate the file and then open and calculate the 0438 // list of fields if necessary. 0439 QStringList SourceListPlugin::fieldList(QSettings *cfg, 0440 const QString& filename, 0441 const QString& type, 0442 QString *typeSuggestion, 0443 bool *complete) const { 0444 Q_UNUSED(cfg) 0445 Q_UNUSED(filename) 0446 Q_UNUSED(type) 0447 0448 if (complete) { 0449 *complete = true; 0450 } 0451 0452 if (typeSuggestion) { 0453 *typeSuggestion = "Source List"; 0454 } 0455 0456 QStringList fieldList; 0457 return fieldList; 0458 } 0459 0460 0461 // The main function used to determine if this plugin knows how to process the provided file. 0462 // Each datasource plugin should check the file and return a number between 0 and 100 based 0463 // on the likelyhood of the file being this type. 100 should only be returned if there is no way 0464 // that the file could be any datasource other than this one. 0465 int SourceListPlugin::understands(QSettings *cfg, const QString& filename) const { 0466 Q_UNUSED(cfg) 0467 0468 if (!QFile::exists(filename)) { 0469 return 0; 0470 } 0471 0472 QFile f(filename); 0473 if (f.open(QIODevice::ReadOnly)) { 0474 0475 QByteArray line; 0476 int i; 0477 0478 for (i=0; i<5; i++) { 0479 line = f.readLine(5000).trimmed(); 0480 if (line.isEmpty()) { 0481 break; 0482 } 0483 if (!QFile::exists(line) && !QFileInfo(line).isDir()) { 0484 return 0; 0485 } 0486 } 0487 0488 if (i>0) { // all lines (1 or more) listed files 0489 return 80; 0490 } 0491 } 0492 return 0; 0493 } 0494 0495 0496 0497 bool SourceListPlugin::supportsTime(QSettings *cfg, const QString& filename) const { 0498 //FIXME 0499 Q_UNUSED(cfg) 0500 Q_UNUSED(filename) 0501 return true; 0502 } 0503 0504 0505 QStringList SourceListPlugin::provides() const { 0506 QStringList rc; 0507 rc += sourceListTypeString; 0508 return rc; 0509 } 0510 0511 0512 // Request for this plugins configuration widget. 0513 Kst::DataSourceConfigWidget *SourceListPlugin::configWidget(QSettings *cfg, const QString& filename) const { 0514 Q_UNUSED(cfg) 0515 Q_UNUSED(filename) 0516 return 0;; 0517 0518 } 0519 0520 #ifndef QT5 0521 Q_EXPORT_PLUGIN2(kstdata_SourceList, SourceListPlugin) 0522 #endif 0523 0524 // vim: ts=2 sw=2 et