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