00001
00002
00003 #include <QDir>
00004 #include <QFileInfo>
00005 #include <QString>
00006 #include <QStringList>
00007 #include <QApplication>
00008
00009
00010 #include <mythcontext.h>
00011 #include <mythdbcon.h>
00012 #include <mythdb.h>
00013 #include <mythprogressdialog.h>
00014 #include <mythdirs.h>
00015
00016
00017 #include "weatherScreen.h"
00018 #include "weatherSource.h"
00019 #include "sourceManager.h"
00020
00021 #define LOC QString("SourceManager: ")
00022 #define LOC_ERR QString("SourceManager Error: ")
00023
00024 SourceManager::SourceManager()
00025 {
00026 findScriptsDB();
00027 setupSources();
00028 }
00029
00030 SourceManager::~SourceManager()
00031 {
00032 clearSources();
00033 }
00034
00035 bool SourceManager::findScriptsDB()
00036 {
00037 MSqlQuery db(MSqlQuery::InitCon());
00038 QString query =
00039 "SELECT DISTINCT wss.sourceid, source_name, update_timeout, "
00040 "retrieve_timeout, path, author, version, email, types "
00041 "FROM weathersourcesettings wss "
00042 "LEFT JOIN weatherdatalayout wdl "
00043 "ON wss.sourceid = wdl.weathersourcesettings_sourceid "
00044 "WHERE hostname = :HOST;";
00045
00046 db.prepare(query);
00047 db.bindValue(":HOST", gCoreContext->GetHostName());
00048 if (!db.exec())
00049 {
00050 MythDB::DBError("Finding weather source scripts for host", db);
00051 return false;
00052 }
00053
00054 while (db.next())
00055 {
00056 QFileInfo fi(db.value(4).toString());
00057
00058 if (!fi.isExecutable())
00059 {
00060
00061
00062 continue;
00063 }
00064 ScriptInfo *si = new ScriptInfo;
00065 si->id = db.value(0).toInt();
00066 si->name = db.value(1).toString();
00067 si->updateTimeout = db.value(2).toUInt() * 1000;
00068 si->scriptTimeout = db.value(3).toUInt();
00069 si->path = fi.absolutePath();
00070 si->program = fi.absoluteFilePath();
00071 si->author = db.value(5).toString();
00072 si->version = db.value(6).toString();
00073 si->email = db.value(7).toString();
00074 si->types = db.value(8).toString().split(",");
00075 m_scripts.append(si);
00076 }
00077
00078 return true;
00079 }
00080
00081 bool SourceManager::findScripts()
00082 {
00083 QString path = GetShareDir() + "mythweather/scripts/";
00084 QDir dir(path);
00085 dir.setFilter(QDir::Executable | QDir::Files | QDir::Dirs);
00086
00087 if (!dir.exists())
00088 {
00089 LOG(VB_GENERAL, LOG_ERR, "MythWeather: Scripts directory not found");
00090 return false;
00091 }
00092 QString busymessage = tr("Searching for scripts");
00093
00094 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("weather stack");
00095 if (popupStack == NULL)
00096 popupStack = GetMythMainWindow()->GetStack("popup stack");
00097
00098 MythUIBusyDialog *busyPopup = new MythUIBusyDialog(busymessage, popupStack,
00099 "mythweatherbusydialog");
00100
00101 if (busyPopup->Create())
00102 {
00103 popupStack->AddScreen(busyPopup, false);
00104 }
00105 else
00106 {
00107 delete busyPopup;
00108 busyPopup = NULL;
00109 }
00110
00111 qApp->processEvents();
00112
00113 recurseDirs(dir);
00114
00115
00116 MSqlQuery db(MSqlQuery::InitCon());
00117
00118 db.prepare("SELECT sourceid, path FROM weathersourcesettings "
00119 "WHERE hostname = :HOST;");
00120 db.bindValue(":HOST", gCoreContext->GetHostName());
00121 if (!db.exec())
00122 MythDB::DBError("SourceManager::findScripts - select", db);
00123 QStringList toRemove;
00124 while (db.next())
00125 {
00126 QFileInfo fi(db.value(1).toString());
00127 if (!fi.isExecutable())
00128 {
00129 toRemove << db.value(0).toString();
00130 LOG(VB_GENERAL, LOG_ERR, QString("'%1' no longer exists")
00131 .arg(fi.absoluteFilePath()));
00132 }
00133 }
00134
00135 db.prepare("DELETE FROM weathersourcesettings WHERE sourceid = :ID;");
00136 for (int i = 0; i < toRemove.count(); ++i)
00137 {
00138 db.bindValue(":ID", toRemove[i]);
00139 if (!db.exec())
00140 {
00141
00142 }
00143 }
00144
00145 if (busyPopup)
00146 {
00147 busyPopup->Close();
00148 busyPopup = NULL;
00149 }
00150
00151 return m_scripts.count() > 0;
00152 }
00153
00154 void SourceManager::clearSources()
00155 {
00156 while (!m_scripts.isEmpty())
00157 delete m_scripts.takeFirst();
00158 m_scripts.clear();
00159
00160 while (!m_sources.isEmpty())
00161 delete m_sources.takeFirst();
00162 m_sources.clear();
00163 }
00164
00165 void SourceManager::setupSources()
00166 {
00167 MSqlQuery db(MSqlQuery::InitCon());
00168
00169 db.prepare(
00170 "SELECT DISTINCT location, weathersourcesettings_sourceid, "
00171 " weatherscreens.units, weatherscreens.screen_id "
00172 "FROM weatherdatalayout,weatherscreens "
00173 "WHERE weatherscreens.screen_id = weatherscreens_screen_id AND "
00174 " weatherscreens.hostname = :HOST");
00175 db.bindValue(":HOST", gCoreContext->GetHostName());
00176 if (!db.exec())
00177 {
00178 MythDB::DBError("Finding weather sources for this host", db);
00179 return;
00180 }
00181
00182 m_sourcemap.clear();
00183
00184 while (db.next())
00185 {
00186 QString loc = db.value(0).toString();
00187 uint sourceid = db.value(1).toUInt();
00188 units_t units = db.value(2).toUInt();
00189 uint screen = db.value(3).toUInt();
00190 const WeatherSource *src = needSourceFor(sourceid, loc, units);
00191 if (src)
00192 m_sourcemap.insert((long)screen, src);
00193 }
00194 }
00195
00196 ScriptInfo *SourceManager::getSourceByName(const QString &name)
00197 {
00198 ScriptInfo *src = 0;
00199 for (int x = 0; x < m_scripts.size(); x++)
00200 {
00201 src = m_scripts.at(x);
00202 if (src->name == name)
00203 {
00204 return src;
00205 }
00206 }
00207
00208 if (!src)
00209 {
00210 LOG(VB_GENERAL, LOG_ERR, "No Source found for " + name);
00211 }
00212
00213 return NULL;
00214 }
00215
00216 QStringList SourceManager::getLocationList(ScriptInfo *si, const QString &str)
00217 {
00218 if (!m_scripts.contains(si))
00219 return QStringList();
00220 WeatherSource *ws = new WeatherSource(si);
00221
00222 QStringList locationList(ws->getLocationList(str));
00223
00224 delete ws;
00225
00226 return locationList;
00227 }
00228
00229 WeatherSource *SourceManager::needSourceFor(int id, const QString &loc,
00230 units_t units)
00231 {
00232
00233 WeatherSource *src;
00234 for (int x = 0; x < m_sources.size(); x++)
00235 {
00236 src = m_sources.at(x);
00237 if (src->getId() == id && src->getLocale() == loc &&
00238 src->getUnits() == units)
00239 {
00240 return src;
00241 }
00242 }
00243
00244
00245 ScriptInfo *si;
00246 for (int x = 0; x < m_scripts.size(); x++)
00247 {
00248 si = m_scripts.at(x);
00249 if (si->id == id)
00250 {
00251 WeatherSource *ws = new WeatherSource(si);
00252 ws->setLocale(loc);
00253 ws->setUnits(units);
00254 m_sources.append(ws);
00255 return ws;
00256 }
00257 }
00258
00259 LOG(VB_GENERAL, LOG_ERR, LOC +
00260 QString("NeedSourceFor: Unable to find source for %1, %2, %3")
00261 .arg(id).arg(loc).arg(units));
00262 return NULL;
00263 }
00264
00265 void SourceManager::startTimers()
00266 {
00267 WeatherSource *src;
00268 for (int x = 0; x < m_sources.size(); x++)
00269 {
00270 src = m_sources.at(x);
00271 src->startUpdateTimer();
00272 }
00273 }
00274
00275 void SourceManager::stopTimers()
00276 {
00277 WeatherSource *src;
00278 for (int x = 0; x < m_sources.size(); x++)
00279 {
00280 src = m_sources.at(x);
00281 src->stopUpdateTimer();
00282 }
00283 }
00284
00285 void SourceManager::doUpdate(bool forceUpdate)
00286 {
00287 WeatherSource *src;
00288 for (int x = 0; x < m_sources.size(); x++)
00289 {
00290 src = m_sources.at(x);
00291 if (src->inUse())
00292 src->startUpdate(forceUpdate);
00293 }
00294 }
00295
00296 bool SourceManager::findPossibleSources(QStringList types,
00297 QList<ScriptInfo *> &sources)
00298 {
00299 ScriptInfo *si;
00300 bool handled;
00301 for (int x = 0; x < m_scripts.size(); x++)
00302 {
00303 si = m_scripts.at(x);
00304 QStringList stypes = si->types;
00305 handled = true;
00306 int i;
00307 for (i = 0; i < types.count() && handled; ++i)
00308 {
00309 handled = stypes.contains(types[i]);
00310 }
00311 if (handled)
00312 sources.append(si);
00313 }
00314
00315 if (sources.count())
00316 return true;
00317
00318 return false;
00319 }
00320
00321 bool SourceManager::connectScreen(uint id, WeatherScreen *screen)
00322 {
00323 if (!screen)
00324 {
00325 LOG(VB_GENERAL, LOG_ERR, LOC +
00326 QString("Cannot connect nonexistent screen 0x%1")
00327 .arg((uint64_t)screen,0,16));
00328
00329 return false;
00330 }
00331
00332 SourceMap::iterator it = m_sourcemap.find(id);
00333 if (it == m_sourcemap.end())
00334 {
00335 LOG(VB_GENERAL, LOG_ERR, LOC +
00336 QString("Cannot connect nonexistent source '%1'").arg(id));
00337
00338 return false;
00339 }
00340
00341 (const_cast<WeatherSource*>(*it))->connectScreen(screen);
00342
00343 return true;
00344 }
00345
00346 bool SourceManager::disconnectScreen(WeatherScreen *screen)
00347 {
00348 if (!screen)
00349 {
00350 LOG(VB_GENERAL, LOG_ERR, LOC +
00351 QString("Cannot disconnect nonexistent screen 0x%1")
00352 .arg((uint64_t)screen,0,16));
00353
00354 return false;
00355 }
00356
00357 SourceMap::iterator it = m_sourcemap.find(screen->getId());
00358 if (it == m_sourcemap.end())
00359 {
00360 LOG(VB_GENERAL, LOG_ERR, LOC +
00361 QString("Cannot disconnect nonexistent source %1")
00362 .arg(screen->getId()));
00363
00364 return false;
00365 }
00366
00367 (const_cast<WeatherSource*>(*it))->disconnectScreen(screen);
00368
00369 return true;
00370 }
00371
00372
00373 void SourceManager::recurseDirs( QDir dir )
00374 {
00375 if (!dir.exists())
00376 return;
00377
00378 dir.setFilter(QDir::Executable | QDir::Files | QDir::Dirs);
00379 QFileInfoList files = dir.entryInfoList();
00380 QFileInfo file;
00381
00382 for (int x = 0; x < files.size(); x++)
00383 {
00384 qApp->processEvents();
00385 file = files.at(x);
00386 if (file.isDir())
00387 {
00388 if (file.fileName() == QString("..")) continue;
00389 if (file.fileName() == QString(".")) continue;
00390 QDir recurseTo(file.filePath());
00391 recurseDirs(recurseTo);
00392 }
00393
00394 if (file.isExecutable() && !(file.isDir()))
00395 {
00396 ScriptInfo *info = WeatherSource::ProbeScript(file);
00397 if (info)
00398 {
00399 m_scripts.append(info);
00400 LOG(VB_FILE, LOG_INFO, QString("Found Script '%1'")
00401 .arg(file.absoluteFilePath()));
00402 }
00403 }
00404 }
00405
00406 return;
00407 }