00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023 #include <math.h>
00024 #include <unistd.h>
00025 #include <cstdlib>
00026
00027 #include <qapplication.h>
00028 #include <qnetwork.h>
00029 #include <qdatetime.h>
00030 #include <qpainter.h>
00031 #include <qdir.h>
00032 #include <qtimer.h>
00033 #include <qregexp.h>
00034
00035 #include "mythtv/mythcontext.h"
00036 #include "mythtv/mythdbcon.h"
00037 #include "mythtv/httpcomms.h"
00038
00039 #include "mythnews.h"
00040
00041 MythNewsBusyDialog::MythNewsBusyDialog(const QString &title)
00042 : MythBusyDialog(title)
00043 {
00044 }
00045
00046 MythNewsBusyDialog::~MythNewsBusyDialog()
00047 {
00048 }
00049
00050 void MythNewsBusyDialog::keyPressEvent(QKeyEvent *e)
00051 {
00052 bool handled = false;
00053 QStringList actions;
00054 if (gContext->GetMainWindow()->TranslateKeyPress("qt", e, actions))
00055 {
00056 for (unsigned int i = 0; i < actions.size() && !handled; i++)
00057 {
00058 QString action = actions[i];
00059 if (action == "ESCAPE")
00060 {
00061 emit cancelAction();
00062 handled = true;
00063 }
00064 }
00065 }
00066
00067 if (!handled)
00068 MythDialog::keyPressEvent(e);
00069 }
00070
00071
00072 MythNews::MythNews(MythMainWindow *parent, const char *name )
00073 : MythDialog(parent, name)
00074 {
00075 qInitNetworkProtocols ();
00076
00077
00078
00079 QString fileprefix = MythContext::GetConfDir();
00080
00081 QDir dir(fileprefix);
00082 if (!dir.exists())
00083 dir.mkdir(fileprefix);
00084 fileprefix += "/MythNews";
00085 dir = QDir(fileprefix);
00086 if (!dir.exists())
00087 dir.mkdir(fileprefix);
00088
00089 zoom = QString("-z %1").arg(gContext->GetNumSetting("WebBrowserZoomLevel",200));
00090 browser = gContext->GetSetting("WebBrowserCommand",
00091 gContext->GetInstallPrefix() +
00092 "/bin/mythbrowser");
00093
00094
00095
00096 m_InColumn = 0;
00097 m_UISites = 0;
00098 m_UIArticles = 0;
00099 m_TimerTimeout = 10*60*1000;
00100 httpGrabber = NULL;
00101
00102 timeFormat = gContext->GetSetting("TimeFormat", "h:mm AP");
00103 dateFormat = gContext->GetSetting("DateFormat", "ddd MMMM d");
00104
00105 setNoErase();
00106 loadTheme();
00107
00108 updateBackground();
00109
00110
00111 m_RetrieveTimer = new QTimer(this);
00112 connect(m_RetrieveTimer, SIGNAL(timeout()),
00113 this, SLOT(slotRetrieveNews()));
00114 m_UpdateFreq = gContext->GetNumSetting("NewsUpdateFrequency", 30);
00115
00116
00117 loadSites();
00118
00119 m_NewsSites.setAutoDelete(true);
00120
00121 m_RetrieveTimer->start(m_TimerTimeout, false);
00122 }
00123
00124 void MythNews::loadSites(void)
00125 {
00126 m_NewsSites.clear();
00127 m_UISites->Reset();
00128
00129 MSqlQuery query(MSqlQuery::InitCon());
00130 query.exec("SELECT name, url, ico, updated FROM newssites ORDER BY name");
00131
00132 if (!query.isActive()) {
00133 VERBOSE(VB_IMPORTANT, "MythNews: Error in loading Sites from DB");
00134 }
00135 else {
00136 QString name;
00137 QString url;
00138 QString icon;
00139 QDateTime time;
00140 while ( query.next() ) {
00141 name = QString::fromUtf8(query.value(0).toString());
00142 url = QString::fromUtf8(query.value(1).toString());
00143 icon = QString::fromUtf8(query.value(2).toString());
00144 time.setTime_t(query.value(3).toUInt());
00145 m_NewsSites.append(new NewsSite(name,url,time));
00146 }
00147 }
00148
00149 for (NewsSite *site = m_NewsSites.first(); site; site = m_NewsSites.next())
00150 {
00151 UIListBtnTypeItem* item =
00152 new UIListBtnTypeItem(m_UISites, site->name());
00153 item->setData(site);
00154
00155 connect(site, SIGNAL(finished(NewsSite*)),
00156 this, SLOT(slotNewsRetrieved(NewsSite*)));
00157 }
00158
00159 slotRetrieveNews();
00160
00161 slotSiteSelected((NewsSite*) m_NewsSites.first());
00162 }
00163
00164 MythNews::~MythNews()
00165 {
00166 m_RetrieveTimer->stop();
00167 delete m_Theme;
00168 }
00169
00170 void MythNews::loadTheme()
00171 {
00172 m_Theme = new XMLParse();
00173 m_Theme->SetWMult(wmult);
00174 m_Theme->SetHMult(hmult);
00175
00176 QDomElement xmldata;
00177 m_Theme->LoadTheme(xmldata, "news", "news-");
00178
00179 for (QDomNode child = xmldata.firstChild(); !child.isNull();
00180 child = child.nextSibling()) {
00181
00182 QDomElement e = child.toElement();
00183 if (!e.isNull()) {
00184
00185 if (e.tagName() == "font") {
00186 m_Theme->parseFont(e);
00187 }
00188 else if (e.tagName() == "container") {
00189 QRect area;
00190 QString name;
00191 int context;
00192 m_Theme->parseContainer(e, name, context, area);
00193
00194 if (name.lower() == "sites")
00195 m_SitesRect = area;
00196 else if (name.lower() == "articles")
00197 m_ArticlesRect = area;
00198 else if (name.lower() == "info")
00199 m_InfoRect = area;
00200 }
00201 else {
00202 VERBOSE(VB_IMPORTANT, QString("Unknown element: %1")
00203 .arg(e.tagName()));
00204 exit(-1);
00205 }
00206 }
00207 }
00208
00209 LayerSet *container = m_Theme->GetSet("sites");
00210 if (!container) {
00211 VERBOSE(VB_IMPORTANT, "MythNews: Failed to get sites container.");
00212 exit(-1);
00213 }
00214
00215 m_UISites = (UIListBtnType*)container->GetType("siteslist");
00216 if (!m_UISites) {
00217 VERBOSE(VB_IMPORTANT, "MythNews: Failed to get sites list area.");
00218 exit(-1);
00219 }
00220
00221 connect(m_UISites, SIGNAL(itemSelected(UIListBtnTypeItem*)),
00222 SLOT(slotSiteSelected(UIListBtnTypeItem*)));
00223
00224 container = m_Theme->GetSet("articles");
00225 if (!container) {
00226 VERBOSE(VB_IMPORTANT, "MythNews: Failed to get articles container.");
00227 exit(-1);
00228 }
00229
00230 m_UIArticles = (UIListBtnType*)container->GetType("articleslist");
00231 if (!m_UIArticles) {
00232 VERBOSE(VB_IMPORTANT, "MythNews: Failed to get articles list area.");
00233 exit(-1);
00234 }
00235
00236 connect(m_UIArticles, SIGNAL(itemSelected(UIListBtnTypeItem*)),
00237 SLOT(slotArticleSelected(UIListBtnTypeItem*)));
00238
00239 m_UISites->SetActive(true);
00240 m_UIArticles->SetActive(false);
00241 }
00242
00243
00244 void MythNews::paintEvent(QPaintEvent *e)
00245 {
00246 QRect r = e->rect();
00247
00248 if (r.intersects(m_SitesRect))
00249 updateSitesView();
00250 if (r.intersects(m_ArticlesRect))
00251 updateArticlesView();
00252 if (r.intersects(m_InfoRect))
00253 updateInfoView();
00254 }
00255
00256 void MythNews::updateBackground(void)
00257 {
00258 QPixmap bground(size());
00259 bground.fill(this, 0, 0);
00260
00261 QPainter tmp(&bground);
00262
00263 LayerSet *container = m_Theme->GetSet("background");
00264 if (container)
00265 {
00266 container->Draw(&tmp, 0, 0);
00267 }
00268
00269 tmp.end();
00270 m_background = bground;
00271
00272 setPaletteBackgroundPixmap(m_background);
00273 }
00274
00275 void MythNews::updateSitesView()
00276 {
00277 QPixmap pix(m_SitesRect.size());
00278 pix.fill(this, m_SitesRect.topLeft());
00279 QPainter p(&pix);
00280
00281 LayerSet* container = m_Theme->GetSet("sites");
00282 if (container) {
00283 container->Draw(&p, 0, 0);
00284 container->Draw(&p, 1, 0);
00285 container->Draw(&p, 2, 0);
00286 container->Draw(&p, 3, 0);
00287 container->Draw(&p, 4, 0);
00288 container->Draw(&p, 5, 0);
00289 container->Draw(&p, 6, 0);
00290 container->Draw(&p, 7, 0);
00291 container->Draw(&p, 8, 0);
00292 }
00293 p.end();
00294
00295 bitBlt(this, m_SitesRect.left(), m_SitesRect.top(),
00296 &pix, 0, 0, -1, -1, Qt::CopyROP);
00297 }
00298
00299 void MythNews::updateArticlesView()
00300 {
00301 QPixmap pix(m_ArticlesRect.size());
00302 pix.fill(this, m_ArticlesRect.topLeft());
00303 QPainter p(&pix);
00304
00305 LayerSet* container = m_Theme->GetSet("articles");
00306 if (container) {
00307 container->Draw(&p, 0, 0);
00308 container->Draw(&p, 1, 0);
00309 container->Draw(&p, 2, 0);
00310 container->Draw(&p, 3, 0);
00311 container->Draw(&p, 4, 0);
00312 container->Draw(&p, 5, 0);
00313 container->Draw(&p, 6, 0);
00314 container->Draw(&p, 7, 0);
00315 container->Draw(&p, 8, 0);
00316 }
00317 p.end();
00318
00319 bitBlt(this, m_ArticlesRect.left(), m_ArticlesRect.top(),
00320 &pix, 0, 0, -1, -1, Qt::CopyROP);
00321 }
00322
00323 void MythNews::updateInfoView()
00324 {
00325 QPixmap pix(m_InfoRect.size());
00326 pix.fill(this, m_InfoRect.topLeft());
00327 QPainter p(&pix);
00328
00329 LayerSet* container = m_Theme->GetSet("info");
00330 if (container)
00331 {
00332 NewsSite *site = 0;
00333 NewsArticle *article = 0;
00334
00335 UIListBtnTypeItem *siteUIItem = m_UISites->GetItemCurrent();
00336 if (siteUIItem && siteUIItem->getData())
00337 site = (NewsSite*) siteUIItem->getData();
00338
00339 UIListBtnTypeItem *articleUIItem = m_UIArticles->GetItemCurrent();
00340 if (articleUIItem && articleUIItem->getData())
00341 article = (NewsArticle*) articleUIItem->getData();
00342
00343 if (m_InColumn == 1)
00344 {
00345 if (article)
00346 {
00347 UITextType *ttype =
00348 (UITextType *)container->GetType("title");
00349 if (ttype)
00350 ttype->SetText(article->title());
00351
00352 ttype =
00353 (UITextType *)container->GetType("description");
00354 if (ttype)
00355 {
00356 QString artText = article->description();
00357
00358 if( artText.find(QRegExp("</(p|P)>")) )
00359 {
00360 artText.replace( QRegExp("<(p|P)>"), "");
00361 artText.replace( QRegExp("</(p|P)>"), "\n\n");
00362 }
00363 else
00364 {
00365 artText.replace( QRegExp("<(p|P)>"), "\n\n");
00366 artText.replace( QRegExp("</(p|P)>"), "");
00367 }
00368 artText.replace( QRegExp("<(br|BR|)/>"), "\n");
00369 artText.replace( QRegExp("<(br|BR|)>"), "\n");
00370
00371
00372
00373 artText.replace( QRegExp("\t"), "");
00374
00375 artText.replace( QRegExp(" "), "");
00376
00377 artText.replace( QRegExp("\n "), "\n");
00378
00379 QRegExp removeHTML(QRegExp("</?.+>"));
00380 removeHTML.setMinimal(true);
00381 artText.remove((const QRegExp&) removeHTML);
00382 artText = artText.stripWhiteSpace();
00383 ttype->SetText(artText);
00384 }
00385
00386 if (article->thumbnail())
00387 {
00388 QString fileprefix = MythContext::GetConfDir();
00389
00390 QDir dir(fileprefix);
00391 if (!dir.exists())
00392 dir.mkdir(fileprefix);
00393
00394 fileprefix += "/MythNews/tcache";
00395
00396 dir = QDir(fileprefix);
00397 if (!dir.exists())
00398 dir.mkdir(fileprefix);
00399
00400 QString url = article->thumbnail();
00401 QString sFilename = QString("%1/%2")
00402 .arg(fileprefix).arg(qChecksum(url,url.length()));
00403
00404 bool exists = QFile::exists(sFilename);
00405 if (!exists)
00406 HttpComms::getHttpFile(sFilename, url, 20000);
00407
00408 UIImageType *itype = (UIImageType *)container->GetType("thumbnail");
00409 if (itype)
00410 {
00411 itype->SetImage(sFilename);
00412 itype->LoadImage();
00413
00414 if (itype->isHidden())
00415 itype->show();
00416 }
00417 }
00418 else
00419 {
00420 if (site->imageURL())
00421 {
00422 QString fileprefix = MythContext::GetConfDir();
00423
00424 QDir dir(fileprefix);
00425 if (!dir.exists())
00426 dir.mkdir(fileprefix);
00427
00428 fileprefix += "/MythNews/scache";
00429
00430 dir = QDir(fileprefix);
00431 if (!dir.exists())
00432 dir.mkdir(fileprefix);
00433
00434 QString sitename = site->name();
00435 QString sFilename(fileprefix + "/" + sitename + ".jpg");
00436 QString url = site->imageURL();
00437
00438 bool exists = QFile::exists(sFilename);
00439 if (!exists)
00440 HttpComms::getHttpFile(sFilename, url, 20000);
00441
00442 UIImageType *itype = (UIImageType *)container->GetType("thumbnail");
00443 if (itype)
00444 {
00445 itype->SetImage(sFilename);
00446 itype->LoadImage();
00447
00448 if (itype->isHidden())
00449 itype->show();
00450 }
00451 }
00452 }
00453 }
00454 }
00455 else
00456 {
00457 UIImageType *itype = (UIImageType *)container->GetType("thumbnail");
00458 if (itype)
00459 {
00460 itype->hide();
00461 }
00462
00463 if (site)
00464 {
00465 UITextType *ttype =
00466 (UITextType *)container->GetType("title");
00467 if (ttype)
00468 ttype->SetText(site->name());
00469
00470 ttype =
00471 (UITextType *)container->GetType("description");
00472 if (ttype)
00473 ttype->SetText(site->description());
00474
00475 if (site->imageURL())
00476 {
00477 QString fileprefix = MythContext::GetConfDir();
00478
00479 QDir dir(fileprefix);
00480 if (!dir.exists())
00481 dir.mkdir(fileprefix);
00482
00483 fileprefix += "/MythNews/scache";
00484
00485 dir = QDir(fileprefix);
00486 if (!dir.exists())
00487 dir.mkdir(fileprefix);
00488
00489 QString sitename = site->name();
00490 QString sFilename(fileprefix + "/" + sitename + ".jpg");
00491 QString url = site->imageURL();
00492
00493 bool exists = QFile::exists(sFilename);
00494 if (!exists)
00495 HttpComms::getHttpFile(sFilename, url, 20000);
00496
00497 UIImageType *itype = (UIImageType *)container->GetType("thumbnail");
00498 if (itype)
00499 {
00500 itype->SetImage(sFilename);
00501 itype->LoadImage();
00502
00503 if (itype->isHidden())
00504 itype->show();
00505 }
00506 }
00507 }
00508 }
00509
00510 UITextType *ttype =
00511 (UITextType *)container->GetType("updated");
00512 if (ttype) {
00513
00514 if (site)
00515 {
00516 QString text(tr("Updated") + " - ");
00517 QDateTime updated(site->lastUpdated());
00518 if (updated.toTime_t() != 0) {
00519 text += site->lastUpdated().toString(dateFormat) + " ";
00520 text += site->lastUpdated().toString(timeFormat);
00521 }
00522 else
00523 text += tr("Unknown");
00524 ttype->SetText(text);
00525 }
00526
00527 if (httpGrabber != NULL)
00528 {
00529 int progress = httpGrabber->getProgress();
00530 int total = httpGrabber->getTotal();
00531 if ((progress > 0) && (total > 0) && (progress < total))
00532 {
00533 float fProgress = (float)progress/total;
00534 QString text = QString("%1 of %2 (%3 percent)")
00535 .arg(formatSize(progress, 2))
00536 .arg(formatSize(total, 2))
00537 .arg(floor(fProgress*100));
00538 ttype->SetText(text);
00539 }
00540 }
00541 }
00542
00543 UIImageType *itype = (UIImageType *)container->GetType("enclosures");
00544 if (itype)
00545 {
00546 if ((article) && (m_InColumn == 1))
00547 {
00548 if (article->enclosure())
00549 {
00550 if (itype->isHidden())
00551 itype->show();
00552 } else {
00553 itype->hide();
00554 }
00555 } else {
00556 itype->hide();
00557 }
00558 }
00559
00560 UIImageType *dtype = (UIImageType *)container->GetType("download");
00561 if (dtype)
00562 {
00563 if ((article) && (m_InColumn == 1))
00564 {
00565 if (article->enclosure())
00566 {
00567 if (dtype->isHidden())
00568 dtype->show();
00569 }
00570 else
00571 dtype->hide();
00572 }
00573 else
00574 dtype->hide();
00575 }
00576
00577 container->Draw(&p, 0, 0);
00578 container->Draw(&p, 1, 0);
00579 container->Draw(&p, 2, 0);
00580 container->Draw(&p, 3, 0);
00581 container->Draw(&p, 4, 0);
00582 container->Draw(&p, 5, 0);
00583 container->Draw(&p, 6, 0);
00584 container->Draw(&p, 7, 0);
00585 container->Draw(&p, 8, 0);
00586 }
00587
00588 p.end();
00589
00590
00591 bitBlt(this, m_InfoRect.left(), m_InfoRect.top(),
00592 &pix, 0, 0, -1, -1, Qt::CopyROP);
00593 }
00594
00595 QString MythNews::formatSize(long long bytes, int prec)
00596 {
00597 long long sizeKB = bytes / 1024;
00598
00599 if (sizeKB>1024*1024*1024)
00600 {
00601 double sizeGB = sizeKB/(1024*1024*1024.0);
00602 return QString("%1 TB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
00603 }
00604 else if (sizeKB>1024*1024)
00605 {
00606 double sizeGB = sizeKB/(1024*1024.0);
00607 return QString("%1 GB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
00608 }
00609 else if (sizeKB>1024)
00610 {
00611 double sizeMB = sizeKB/1024.0;
00612 return QString("%1 MB").arg(sizeMB, 0, 'f', (sizeMB>10)?0:prec);
00613 }
00614
00615 return QString("%1 KB").arg(sizeKB);
00616 }
00617
00618 void MythNews::keyPressEvent(QKeyEvent *e)
00619 {
00620 if (!e) return;
00621
00622 bool handled = false;
00623 QStringList actions;
00624 gContext->GetMainWindow()->TranslateKeyPress("News", e, actions);
00625
00626 for (unsigned int i = 0; i < actions.size() && !handled; i++)
00627 {
00628 QString action = actions[i];
00629 handled = true;
00630
00631 if (action == "UP")
00632 cursorUp();
00633 else if (action == "PAGEUP")
00634 cursorUp(true);
00635 else if (action == "DOWN")
00636 cursorDown();
00637 else if (action == "PAGEDOWN")
00638 cursorDown(true);
00639 else if (action == "LEFT")
00640 cursorLeft();
00641 else if (action == "RIGHT")
00642 cursorRight();
00643 else if (action == "RETRIEVENEWS")
00644 slotRetrieveNews();
00645 else if(action == "SELECT")
00646 slotViewArticle();
00647 else if (action == "CANCEL")
00648 cancelRetrieve();
00649 else if (action == "MENU")
00650 showMenu();
00651 else
00652 handled = false;
00653 }
00654
00655 if (!handled)
00656 MythDialog::keyPressEvent(e);
00657 }
00658
00659 void MythNews::cursorUp(bool page)
00660 {
00661 UIListBtnType::MovementUnit unit = page ? UIListBtnType::MovePage : UIListBtnType::MoveItem;
00662
00663 if (m_InColumn == 0) {
00664 m_UISites->MoveUp(unit);
00665 }
00666 else {
00667 m_UIArticles->MoveUp(unit);
00668 }
00669 }
00670
00671 void MythNews::cursorDown(bool page)
00672 {
00673 UIListBtnType::MovementUnit unit = page ? UIListBtnType::MovePage : UIListBtnType::MoveItem;
00674
00675 if (m_InColumn == 0) {
00676 m_UISites->MoveDown(unit);
00677 }
00678 else {
00679 m_UIArticles->MoveDown(unit);
00680 }
00681 }
00682
00683 void MythNews::cursorRight()
00684 {
00685 if (m_InColumn == 1)
00686 {
00687 slotViewArticle();
00688 return;
00689 }
00690
00691 m_InColumn++;
00692
00693 m_UISites->SetActive(false);
00694 m_UIArticles->SetActive(true);
00695
00696 update(m_SitesRect);
00697 update(m_ArticlesRect);
00698 update(m_InfoRect);
00699 }
00700
00701 void MythNews::cursorLeft()
00702 {
00703 if (m_InColumn == 0)
00704 {
00705 accept();
00706 return;
00707 }
00708
00709 m_InColumn--;
00710
00711 m_UISites->SetActive(true);
00712 m_UIArticles->SetActive(false);
00713
00714 update(m_SitesRect);
00715 update(m_ArticlesRect);
00716 update(m_InfoRect);
00717 }
00718
00719 void MythNews::slotRetrieveNews()
00720 {
00721 if (m_NewsSites.count() == 0)
00722 return;
00723
00724 m_RetrieveTimer->stop();
00725
00726 for (NewsSite* site = m_NewsSites.first(); site; site = m_NewsSites.next())
00727 {
00728 if (site->timeSinceLastUpdate() > m_UpdateFreq)
00729 site->retrieve();
00730 else
00731 processAndShowNews(site);
00732 }
00733
00734 m_RetrieveTimer->start(m_TimerTimeout, false);
00735 }
00736
00737 void MythNews::slotNewsRetrieved(NewsSite* site)
00738 {
00739 unsigned int updated = site->lastUpdated().toTime_t();
00740
00741 MSqlQuery query(MSqlQuery::InitCon());
00742 query.prepare("UPDATE newssites SET updated = :UPDATED "
00743 "WHERE name = :NAME ;");
00744 query.bindValue(":UPDATED", updated);
00745 query.bindValue(":NAME", site->name().utf8());
00746 if (!query.exec() || !query.isActive())
00747 MythContext::DBError("news update time", query);
00748
00749 processAndShowNews(site);
00750 }
00751
00752 void MythNews::cancelRetrieve()
00753 {
00754 for (NewsSite* site = m_NewsSites.first(); site;
00755 site = m_NewsSites.next()) {
00756 site->stop();
00757 processAndShowNews(site);
00758 }
00759 }
00760
00761 void MythNews::processAndShowNews(NewsSite* site)
00762 {
00763 if (!site)
00764 return;
00765
00766 site->process();
00767
00768 UIListBtnTypeItem *siteUIItem = m_UISites->GetItemCurrent();
00769 if (!siteUIItem || !siteUIItem->getData())
00770 return;
00771
00772 if (site == (NewsSite*) siteUIItem->getData()) {
00773
00774 m_UIArticles->Reset();
00775
00776 for (NewsArticle* article = site->articleList().first(); article;
00777 article = site->articleList().next()) {
00778 UIListBtnTypeItem* item =
00779 new UIListBtnTypeItem(m_UIArticles, article->title());
00780 item->setData(article);
00781 }
00782
00783 update(m_ArticlesRect);
00784 update(m_InfoRect);
00785 }
00786 }
00787 void MythNews::slotSiteSelected(NewsSite* site)
00788 {
00789 if(!site)
00790 return;
00791
00792 m_UIArticles->Reset();
00793
00794 for (NewsArticle* article = site->articleList().first(); article;
00795 article = site->articleList().next()) {
00796 UIListBtnTypeItem* item =
00797 new UIListBtnTypeItem(m_UIArticles, article->title());
00798 item->setData(article);
00799 }
00800
00801 update(m_SitesRect);
00802 update(m_ArticlesRect);
00803 update(m_InfoRect);
00804 }
00805
00806 void MythNews::slotSiteSelected(UIListBtnTypeItem *item)
00807 {
00808 if (!item || !item->getData())
00809 return;
00810
00811 slotSiteSelected((NewsSite*) item->getData());
00812 }
00813
00814 void MythNews::slotArticleSelected(UIListBtnTypeItem*)
00815 {
00816 update(m_ArticlesRect);
00817 update(m_InfoRect);
00818 }
00819
00820 void MythNews::slotProgressCancelled()
00821 {
00822 abortHttp = true;
00823 }
00824
00825 void MythNews::createProgress(QString title)
00826 {
00827 busy = new MythNewsBusyDialog(title);
00828 busy->start();
00829 connect(busy, SIGNAL(cancelAction()),
00830 SLOT(slotProgressCancelled()));
00831 }
00832
00833 bool MythNews::getHttpFile(QString sFilename, QString cmdURL)
00834 {
00835 int redirectCount = 0;
00836 int timeoutCount = 0;
00837 QByteArray data(0);
00838 bool res = false;
00839 httpGrabber = NULL;
00840 QString hostname = "";
00841
00842 busy = NULL;
00843 createProgress(QObject::tr("Downloading media..."));
00844 while (1)
00845 {
00846 QUrl qurl(cmdURL);
00847 if (hostname == "")
00848 hostname = qurl.host();
00849
00850 if (!qurl.hasHost())
00851 qurl.setHost(hostname);
00852
00853 if (httpGrabber != NULL)
00854 delete httpGrabber;
00855
00856 httpGrabber = new HttpComms;
00857 abortHttp = false;
00858
00859 httpGrabber->request(qurl, -1, true);
00860
00861 while ((!httpGrabber->isDone()) && (!abortHttp))
00862 {
00863 update(m_InfoRect);
00864 qApp->processEvents();
00865 usleep(100000);
00866 }
00867
00868 if (abortHttp)
00869 break;
00870
00871
00872 if (!httpGrabber->getRedirectedURL().isEmpty())
00873 {
00874 if (redirectCount++ < 3)
00875 cmdURL = httpGrabber->getRedirectedURL();
00876
00877
00878 timeoutCount = 0;
00879 continue;
00880 }
00881
00882 data = httpGrabber->getRawData();
00883
00884 if (data.size() > 0)
00885 {
00886 QFile file(sFilename);
00887 if (file.open( IO_WriteOnly ))
00888 {
00889 QDataStream stream(& file);
00890 stream.writeRawBytes( (const char*) (data), data.size() );
00891 file.close();
00892 res = true;
00893 }
00894 }
00895 break;
00896 }
00897
00898 delete httpGrabber;
00899 httpGrabber = NULL;
00900 delete busy;
00901 return res;
00902
00903 }
00904
00905 void MythNews::slotViewArticle()
00906 {
00907 UIListBtnTypeItem *articleUIItem = m_UIArticles->GetItemCurrent();
00908
00909 if (articleUIItem && articleUIItem->getData())
00910 {
00911 NewsArticle *article = (NewsArticle*) articleUIItem->getData();
00912 if(article)
00913 {
00914 if (article->enclosure())
00915 {
00916 QString cmdURL(article->enclosure());
00917
00918
00919 if (cmdURL.contains("youtube.com"))
00920 {
00921 cmdURL = QString(article->mediaURL());
00922 QString mediaPage = HttpComms::getHttp(cmdURL);
00923 if (mediaPage)
00924 {
00925
00926
00927
00928 int playerPos = mediaPage.find("swfArgs") + 7;
00929
00930 int tArgStart = mediaPage.find("\"t\": \"", playerPos) + 6;
00931 int tArgEnd = mediaPage.find("\"", tArgStart);
00932 QString tArgString = mediaPage.mid(tArgStart, tArgEnd - tArgStart);
00933
00934 int vidStart = mediaPage.find("\"video_id\": \"", playerPos) + 13;
00935 int vidEnd = mediaPage.find("\"", vidStart);
00936 QString vidString = mediaPage.mid(vidStart, vidEnd - vidStart);
00937
00938 cmdURL = QString("http://youtube.com/get_video.php?video_id=%2&t=%1").arg(tArgString).arg(vidString);
00939 VERBOSE(VB_GENERAL, QString("MythNews: VideoURL %1").arg(cmdURL));
00940 }
00941 }
00942
00943 QString fileprefix = MythContext::GetConfDir();
00944
00945 QDir dir(fileprefix);
00946 if (!dir.exists())
00947 dir.mkdir(fileprefix);
00948
00949 fileprefix += "/MythNews";
00950
00951 dir = QDir(fileprefix);
00952 if (!dir.exists())
00953 dir.mkdir(fileprefix);
00954
00955 QString sFilename(fileprefix + "/newstempfile");
00956
00957 if (getHttpFile(sFilename, cmdURL))
00958 {
00959 qApp->unlock();
00960 playVideo(sFilename);
00961 qApp->lock();
00962 }
00963 } else {
00964 QString cmdUrl(article->articleURL());
00965 cmdUrl.replace('\'', "%27");
00966
00967 QString geometry = QString(" -x %1 -y %2 -w %3 -h %4 ")
00968 .arg(gContext->GetMainWindow()->x())
00969 .arg(gContext->GetMainWindow()->y())
00970 .arg(gContext->GetMainWindow()->width())
00971 .arg(gContext->GetMainWindow()->height());
00972
00973 if (!gContext->GetMainWindow()->testWFlags(Qt::WStyle_NoBorder))
00974 geometry += " -g ";
00975
00976 QString cmd = QString("%1 %2 %3 '%4'")
00977 .arg(browser)
00978 .arg(geometry)
00979 .arg(zoom)
00980 .arg(cmdUrl);
00981 gContext->GetMainWindow()->AllowInput(false);
00982 myth_system(cmd, MYTH_SYSTEM_DONT_BLOCK_PARENT);
00983 gContext->GetMainWindow()->AllowInput(true);
00984 }
00985 }
00986 }
00987 }
00988
00989 bool MythNews::showEditDialog(bool edit)
00990 {
00991 MythPopupBox *popup = new MythPopupBox(GetMythMainWindow(), "edit news site");
00992
00993 QVBoxLayout *vbox = new QVBoxLayout(NULL, 0, (int)(10 * hmult));
00994 QHBoxLayout *hbox = new QHBoxLayout(vbox, (int)(10 * hmult));
00995
00996 QString title;
00997 if (edit)
00998 title = tr("Edit Site Details");
00999 else
01000 title = tr("Enter Site Details");
01001
01002 QLabel *label = new QLabel(title, popup);
01003 QFont font = label->font();
01004 font.setPointSize(int (font.pointSize() * 1.2));
01005 font.setBold(true);
01006 label->setFont(font);
01007 label->setPaletteForegroundColor(QColor("yellow"));
01008 label->setAlignment(Qt::AlignCenter);
01009 label->setBackgroundOrigin(WindowOrigin);
01010 label->setSizePolicy(QSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)));
01011 label->setMinimumWidth((int)(500 * wmult));
01012 label->setMaximumWidth((int)(500 * wmult));
01013 hbox->addWidget(label);
01014
01015 hbox = new QHBoxLayout(vbox, (int)(10 * hmult));
01016 label = new QLabel(tr("Name:"), popup, "nopopsize");
01017 label->setBackgroundOrigin(WindowOrigin);
01018 label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
01019 label->setMinimumWidth((int)(110 * wmult));
01020 label->setMaximumWidth((int)(110 * wmult));
01021 hbox->addWidget(label);
01022
01023 MythRemoteLineEdit *titleEditor = new MythRemoteLineEdit(popup);
01024 titleEditor->setFocus();
01025 hbox->addWidget(titleEditor);
01026
01027 hbox = new QHBoxLayout(vbox, (int)(10 * hmult));
01028 label = new QLabel(tr("URL:"), popup, "nopopsize");
01029 label->setBackgroundOrigin(WindowOrigin);
01030 label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
01031 label->setMinimumWidth((int)(110 * wmult));
01032 label->setMaximumWidth((int)(110 * wmult));
01033 hbox->addWidget(label);
01034
01035 MythRemoteLineEdit *urlEditor = new MythRemoteLineEdit(popup);
01036 hbox->addWidget(urlEditor);
01037
01038 hbox = new QHBoxLayout(vbox, (int)(10 * hmult));
01039 label = new QLabel(tr("Icon:"), popup, "nopopsize");
01040 label->setBackgroundOrigin(WindowOrigin);
01041 label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
01042 label->setMinimumWidth((int)(110 * wmult));
01043 label->setMaximumWidth((int)(110 * wmult));
01044 hbox->addWidget(label);
01045
01046 MythRemoteLineEdit *iconEditor = new MythRemoteLineEdit(popup);
01047 hbox->addWidget(iconEditor);
01048
01049 popup->addLayout(vbox, 0);
01050
01051 popup->addButton(tr("OK"), popup, SLOT(accept()));
01052 popup->addButton(tr("Cancel"), popup, SLOT(reject()));
01053
01054 QString siteName = "";
01055 if (edit)
01056 {
01057 UIListBtnTypeItem *siteUIItem = m_UISites->GetItemCurrent();
01058
01059 if (siteUIItem && siteUIItem->getData())
01060 {
01061 NewsSite *site = (NewsSite*) siteUIItem->getData();
01062 if(site)
01063 {
01064 siteName = site->name();
01065 titleEditor->setText(site->name());
01066 urlEditor->setText(site->url());
01067 }
01068 }
01069 }
01070
01071 DialogCode res = popup->ExecPopup();
01072
01073 if (kDialogCodeAccepted == res)
01074 {
01075 if (edit && siteName != "")
01076 removeFromDB(siteName);
01077 insertInDB(titleEditor->text(), urlEditor->text(), iconEditor->text(), "custom");
01078 loadSites();
01079 }
01080
01081 popup->deleteLater();
01082
01083 return (kDialogCodeAccepted == res);
01084 }
01085
01086 void MythNews::showMenu()
01087 {
01088 menu = new MythPopupBox(GetMythMainWindow(),"popupMenu");
01089
01090 QButton *temp = menu->addButton(tr("Edit News Site"), this, SLOT(editNewsSite()));
01091 menu->addButton(tr("Add News Site"), this, SLOT(addNewsSite()));
01092 menu->addButton(tr("Delete News Site"), this, SLOT(deleteNewsSite()));
01093 menu->addButton(tr("Cancel"), this, SLOT(cancelMenu()));
01094 temp->setFocus();
01095
01096 menu->ShowPopup(this, SLOT(cancelMenu()));
01097 }
01098
01099 void MythNews::cancelMenu()
01100 {
01101 if (menu)
01102 {
01103 menu->deleteLater();
01104 menu=NULL;
01105 }
01106 }
01107
01108 void MythNews::editNewsSite()
01109 {
01110 cancelMenu();
01111 showEditDialog(true);
01112 }
01113
01114 void MythNews::addNewsSite()
01115 {
01116 cancelMenu();
01117 showEditDialog(false);
01118 }
01119
01120 void MythNews::deleteNewsSite()
01121 {
01122 cancelMenu();
01123
01124 UIListBtnTypeItem *siteUIItem = m_UISites->GetItemCurrent();
01125
01126 QString siteName;
01127 if (siteUIItem && siteUIItem->getData())
01128 {
01129 NewsSite *site = (NewsSite*) siteUIItem->getData();
01130 if(site)
01131 {
01132 siteName = site->name();
01133
01134 if (MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(), QObject::tr("MythNews"),
01135 QObject::tr("Are you sure you want to delete this news site\n\n%1")
01136 .arg(siteName), true))
01137 {
01138 removeFromDB(siteName);
01139 loadSites();
01140 }
01141 }
01142 }
01143 }
01144
01145 bool MythNews::findInDB(const QString& name)
01146 {
01147 bool val = false;
01148
01149 MSqlQuery query(MSqlQuery::InitCon());
01150 query.prepare("SELECT name FROM newssites WHERE name = :NAME ;");
01151 query.bindValue(":NAME", name.utf8());
01152 if (!query.exec() || !query.isActive()) {
01153 MythContext::DBError("new find in db", query);
01154 return val;
01155 }
01156
01157 val = query.numRowsAffected() > 0;
01158
01159 return val;
01160 }
01161
01162 bool MythNews::insertInDB(const QString &name, const QString &url,
01163 const QString &icon, const QString &category)
01164 {
01165 if (findInDB(name))
01166 return false;
01167
01168 MSqlQuery query(MSqlQuery::InitCon());
01169 query.prepare("INSERT INTO newssites (name,category,url,ico) "
01170 " VALUES( :NAME, :CATEGORY, :URL, :ICON );");
01171 query.bindValue(":NAME", name.utf8());
01172 query.bindValue(":CATEGORY", category.utf8());
01173 query.bindValue(":URL", url.utf8());
01174 query.bindValue(":ICON", icon.utf8());
01175 if (!query.exec() || !query.isActive()) {
01176 MythContext::DBError("news: inserting in DB", query);
01177 return false;
01178 }
01179
01180 return (query.numRowsAffected() > 0);
01181 }
01182
01183 bool MythNews::removeFromDB(const QString &name)
01184 {
01185 MSqlQuery query(MSqlQuery::InitCon());
01186 query.prepare("DELETE FROM newssites WHERE name = :NAME ;");
01187 query.bindValue(":NAME", name.utf8());
01188 if (!query.exec() || !query.isActive()) {
01189 MythContext::DBError("news: delete from db", query);
01190 return false;
01191 }
01192
01193 return (query.numRowsAffected() > 0);
01194 }
01195
01196 void MythNews::playVideo(const QString &filename)
01197 {
01198 QString command_string = gContext->GetSetting("VideoDefaultPlayer");
01199
01200 gContext->sendPlaybackStart();
01201
01202 if ((command_string.find("Internal", 0, false) > -1) ||
01203 (command_string.length() < 1))
01204 {
01205 command_string = "Internal";
01206 gContext->GetMainWindow()->HandleMedia(command_string, filename);
01207 }
01208 else
01209 {
01210 if (command_string.contains("%s"))
01211 command_string = command_string.replace(QRegExp("%s"), filename);
01212
01213 myth_system(command_string);
01214 }
01215
01216 gContext->sendPlaybackEnd();
01217 }