MythTV  0.26-pre
sourceManager.cpp
Go to the documentation of this file.
00001 
00002 // QT headers
00003 #include <QDir>
00004 #include <QFileInfo>
00005 #include <QString>
00006 #include <QStringList>
00007 #include <QApplication>
00008 
00009 // MythTV headers
00010 #include <mythcontext.h>
00011 #include <mythdbcon.h>
00012 #include <mythdb.h>
00013 #include <mythprogressdialog.h>
00014 #include <mythdirs.h>
00015 
00016 // MythWeather headers
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             // scripts will be deleted from db in the more robust (i.e. slower)
00061             // findScripts() -- run when entering setup
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     // run through and see if any scripts have been deleted
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             // MythDB::DBError("Deleting weather source settings", db);
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     // matching source exists?
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     // no matching source, make one
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 // Recurses dir for script files
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends