00001 #include <QDomDocument>
00002 #include <QDateTime>
00003 #include <QImageReader>
00004
00005
00006 #include <mythuibutton.h>
00007 #include <mythuibuttonlist.h>
00008 #include <mythuitextedit.h>
00009 #include <mythuicheckbox.h>
00010 #include <mythuifilebrowser.h>
00011 #include <mythmainwindow.h>
00012 #include <mythdialogbox.h>
00013 #include <mythmiscutil.h>
00014 #include <mythcontext.h>
00015 #include <mythdbcon.h>
00016 #include <httpcomms.h>
00017 #include <mythdirs.h>
00018 #include <netutils.h>
00019 #include <rssparse.h>
00020
00021
00022 #include "rsseditor.h"
00023
00024 #define LOC QString("RSSEditor: ")
00025 #define LOC_WARN QString("RSSEditor, Warning: ")
00026 #define LOC_ERR QString("RSSEditor, Error: ")
00027
00028 namespace
00029 {
00030 const QString CEID_NEWIMAGE = "image";
00031
00032 QStringList GetSupportedImageExtensionFilter()
00033 {
00034 QStringList ret;
00035
00036 QList<QByteArray> exts = QImageReader::supportedImageFormats();
00037 for (QList<QByteArray>::iterator p = exts.begin(); p != exts.end(); ++p)
00038 {
00039 ret.append(QString("*.").append(*p));
00040 }
00041
00042 return ret;
00043 }
00044 }
00045
00050 RSSEditPopup::RSSEditPopup(
00051 const QString &url, bool edit,
00052 MythScreenStack *parent, const QString &name) :
00053 MythScreenType(parent, name),
00054 m_site(NULL),
00055 m_urlText(url), m_editing(edit),
00056 m_thumbImage(NULL), m_thumbButton(NULL),
00057 m_urlEdit(NULL), m_titleEdit(NULL),
00058 m_descEdit(NULL), m_authorEdit(NULL),
00059 m_okButton(NULL), m_cancelButton(NULL),
00060 m_download(NULL), m_manager(NULL),
00061 m_reply(NULL)
00062 {
00063 }
00064
00065 RSSEditPopup::~RSSEditPopup()
00066 {
00067 if (m_manager)
00068 {
00069 m_manager->disconnect();
00070 m_manager->deleteLater();
00071 m_manager = NULL;
00072 }
00073 }
00074
00075 bool RSSEditPopup::Create(void)
00076 {
00077
00078 bool foundtheme = LoadWindowFromXML("netvision-ui.xml", "rsseditpopup", this);
00079
00080 if (!foundtheme)
00081 return false;
00082
00083 bool err = false;
00084 UIUtilE::Assign(this, m_urlEdit, "url", &err);
00085 UIUtilE::Assign(this, m_titleEdit, "title", &err);
00086 UIUtilE::Assign(this, m_descEdit, "description", &err);
00087 UIUtilE::Assign(this, m_authorEdit, "author", &err);
00088 UIUtilE::Assign(this, m_download, "download", &err);
00089 UIUtilE::Assign(this, m_okButton, "ok", &err);
00090 UIUtilE::Assign(this, m_cancelButton, "cancel", &err);
00091 UIUtilE::Assign(this, m_thumbButton, "preview_browse", &err);
00092 UIUtilE::Assign(this, m_thumbImage, "preview", &err);
00093
00094 if (err)
00095 {
00096 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditpopup'");
00097 return false;
00098 }
00099
00100 connect(m_okButton, SIGNAL(Clicked()), this, SLOT(parseAndSave()));
00101 connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
00102 connect(m_thumbButton, SIGNAL(Clicked()), this, SLOT(doFileBrowser()));
00103
00104 m_urlEdit->SetMaxLength(0);
00105 m_titleEdit->SetMaxLength(255);
00106 m_descEdit->SetMaxLength(0);
00107 m_authorEdit->SetMaxLength(255);
00108
00109 if (m_editing)
00110 {
00111 m_site = findByURL(m_urlText, VIDEO_PODCAST);
00112
00113 m_urlEdit->SetText(m_urlText);
00114 m_titleEdit->SetText(m_site->GetTitle());
00115 m_descEdit->SetText(m_site->GetDescription());
00116 m_authorEdit->SetText(m_site->GetAuthor());
00117
00118 QString thumb = m_site->GetImage();
00119 if (!thumb.isEmpty())
00120 {
00121 m_thumbImage->SetFilename(thumb);
00122 m_thumbImage->Load();
00123 }
00124
00125 if (m_site->GetDownload() == 1)
00126 m_download->SetCheckState(MythUIStateType::Full);
00127 }
00128
00129 BuildFocusList();
00130
00131 return true;
00132 }
00133
00134 bool RSSEditPopup::keyPressEvent(QKeyEvent *event)
00135 {
00136 if (GetFocusWidget()->keyPressEvent(event))
00137 return true;
00138
00139 bool handled = false;
00140 QStringList actions;
00141 handled = GetMythMainWindow()->TranslateKeyPress("Internet Video", event, actions);
00142
00143 if (!handled && MythScreenType::keyPressEvent(event))
00144 handled = true;
00145
00146 return handled;
00147 }
00148
00149 void RSSEditPopup::parseAndSave(void)
00150 {
00151 if (m_editing)
00152 {
00153 QString title = m_titleEdit->GetText();
00154 QString desc = m_descEdit->GetText();
00155 QString author = m_authorEdit->GetText();
00156 QString link = m_urlEdit->GetText();
00157 QString filename = m_thumbImage->GetFilename();
00158
00159 bool download;
00160 if (m_download->GetCheckState() == MythUIStateType::Full)
00161 download = true;
00162 else
00163 download = false;
00164
00165 removeFromDB(m_urlText, VIDEO_PODCAST);
00166
00167 if (insertInDB(new RSSSite(title, filename, VIDEO_PODCAST,
00168 desc, link, author, download, QDateTime::currentDateTime())))
00169 emit saving();
00170 Close();
00171 }
00172 else
00173 {
00174 m_manager = new QNetworkAccessManager();
00175 QUrl qurl(m_urlEdit->GetText());
00176
00177 m_reply = m_manager->get(QNetworkRequest(qurl));
00178
00179 connect(m_manager, SIGNAL(finished(QNetworkReply*)), this,
00180 SLOT(slotCheckRedirect(QNetworkReply*)));
00181 }
00182 }
00183
00184 QUrl RSSEditPopup::redirectUrl(const QUrl& possibleRedirectUrl,
00185 const QUrl& oldRedirectUrl) const
00186 {
00187 QUrl redirectUrl;
00188 if(!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != oldRedirectUrl)
00189 redirectUrl = possibleRedirectUrl;
00190 return redirectUrl;
00191 }
00192
00193 void RSSEditPopup::slotCheckRedirect(QNetworkReply* reply)
00194 {
00195 QVariant possibleRedirectUrl =
00196 reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
00197
00198 QUrl urlRedirectedTo = redirectUrl(possibleRedirectUrl.toUrl(),
00199 urlRedirectedTo);
00200
00201 if(!urlRedirectedTo.isEmpty())
00202 {
00203 m_urlEdit->SetText(urlRedirectedTo.toString());
00204 m_manager->get(QNetworkRequest(urlRedirectedTo));
00205 }
00206 else
00207 {
00208
00209 slotSave(reply);
00210 }
00211 reply->deleteLater();
00212 }
00213
00214 void RSSEditPopup::slotSave(QNetworkReply* reply)
00215 {
00216 QDomDocument document;
00217 document.setContent(reply->read(reply->bytesAvailable()), true);
00218
00219 QString text = document.toString();
00220
00221 QString title = m_titleEdit->GetText();
00222 QString description = m_descEdit->GetText();
00223 QString author = m_authorEdit->GetText();
00224 QString file = m_thumbImage->GetFilename();
00225
00226 LOG(VB_GENERAL, LOG_DEBUG, QString("Text to Parse: %1").arg(text));
00227
00228 QDomElement root = document.documentElement();
00229 QDomElement channel = root.firstChildElement ("channel");
00230 if (!channel.isNull ())
00231 {
00232 Parse parser;
00233 if (title.isEmpty())
00234 title = channel.firstChildElement("title").text().trimmed();
00235 if (description.isEmpty())
00236 description = channel.firstChildElement("description").text();
00237 if (author.isEmpty())
00238 author = parser.GetAuthor(channel);
00239 if (author.isEmpty())
00240 author = channel.firstChildElement("managingEditor").text();
00241 if (author.isEmpty())
00242 author = channel.firstChildElement("webMaster").text();
00243
00244 QString thumbnailURL = channel.firstChildElement("image").attribute("url");
00245 if (thumbnailURL.isEmpty())
00246 {
00247 QDomElement thumbElem = channel.firstChildElement("image");
00248 if (!thumbElem.isNull())
00249 thumbnailURL = thumbElem.firstChildElement("url").text();
00250 }
00251 if (thumbnailURL.isEmpty())
00252 {
00253 QDomNodeList nodes = channel.elementsByTagNameNS(
00254 "http://www.itunes.com/dtds/podcast-1.0.dtd", "image");
00255 if (nodes.size())
00256 {
00257 thumbnailURL = nodes.at(0).toElement().attributeNode("href").value();
00258 if (thumbnailURL.isEmpty())
00259 thumbnailURL = nodes.at(0).toElement().text();
00260 }
00261 }
00262
00263 bool download;
00264 if (m_download->GetCheckState() == MythUIStateType::Full)
00265 download = true;
00266 else
00267 download = false;
00268
00269 QDateTime updated = QDateTime::currentDateTime();
00270 QString filename("");
00271
00272 if (file.isEmpty())
00273 filename = file;
00274
00275 QString link = m_urlEdit->GetText();
00276
00277 if (!thumbnailURL.isEmpty() && filename.isEmpty())
00278 {
00279 QString fileprefix = GetConfDir();
00280
00281 QDir dir(fileprefix);
00282 if (!dir.exists())
00283 dir.mkdir(fileprefix);
00284
00285 fileprefix += "/MythNetvision";
00286
00287 dir = QDir(fileprefix);
00288 if (!dir.exists())
00289 dir.mkdir(fileprefix);
00290
00291 fileprefix += "/sitecovers";
00292
00293 dir = QDir(fileprefix);
00294 if (!dir.exists())
00295 dir.mkdir(fileprefix);
00296
00297 QFileInfo fi(thumbnailURL);
00298 QString rawFilename = fi.fileName();
00299
00300 filename = QString("%1/%2").arg(fileprefix).arg(rawFilename);
00301
00302 bool exists = QFile::exists(filename);
00303 if (!exists)
00304 HttpComms::getHttpFile(filename, thumbnailURL, 20000, 1, 2);
00305 }
00306 if (insertInDB(new RSSSite(title, filename, VIDEO_PODCAST, description, link,
00307 author, download, QDateTime::currentDateTime())))
00308 emit saving();
00309 }
00310 Close();
00311 }
00312
00313 void RSSEditPopup::doFileBrowser()
00314 {
00315 SelectImagePopup(GetConfDir() + "/MythNetvision" + "/sitecovers", *this, CEID_NEWIMAGE);
00316 }
00317
00318 void RSSEditPopup::SelectImagePopup(const QString &prefix,
00319 QObject &inst, const QString &returnEvent)
00320 {
00321 MythScreenStack *popupStack =
00322 GetMythMainWindow()->GetStack("popup stack");
00323
00324 MythUIFileBrowser *fb = new MythUIFileBrowser(popupStack, prefix);
00325 fb->SetNameFilter(GetSupportedImageExtensionFilter());
00326 if (fb->Create())
00327 {
00328 fb->SetReturnEvent(&inst, returnEvent);
00329 popupStack->AddScreen(fb);
00330 }
00331 else
00332 delete fb;
00333 }
00334
00335 void RSSEditPopup::customEvent(QEvent *levent)
00336 {
00337 if (levent->type() == DialogCompletionEvent::kEventType)
00338 {
00339 DialogCompletionEvent *dce = (DialogCompletionEvent*)(levent);
00340 if (dce->GetId() == CEID_NEWIMAGE)
00341 {
00342 m_thumbImage->SetFilename(dce->GetResultText());
00343 m_thumbImage->Load();
00344 m_thumbImage->Show();
00345 }
00346 }
00347 }
00348
00349 RSSEditor::RSSEditor(MythScreenStack *parent, const QString &name) :
00350 MythScreenType(parent, name), m_lock(QMutex::Recursive),
00351 m_changed(false), m_sites(NULL), m_new(NULL), m_delete(NULL), m_edit(NULL),
00352 m_image(NULL), m_title(NULL), m_url(NULL), m_desc(NULL), m_author(NULL)
00353 {
00354 }
00355
00356 RSSEditor::~RSSEditor()
00357 {
00358 QMutexLocker locker(&m_lock);
00359
00360 if (m_changed)
00361 emit itemsChanged();
00362 }
00363
00364 bool RSSEditor::Create(void)
00365 {
00366 QMutexLocker locker(&m_lock);
00367
00368
00369 bool foundtheme = LoadWindowFromXML("netvision-ui.xml", "rsseditor", this);
00370
00371 if (!foundtheme)
00372 return false;
00373
00374 bool err = false;
00375 UIUtilE::Assign(this, m_sites, "sites", &err);
00376 UIUtilE::Assign(this, m_new, "new", &err);
00377 UIUtilE::Assign(this, m_delete, "delete", &err);
00378 UIUtilE::Assign(this, m_edit, "edit", &err);
00379
00380 UIUtilW::Assign(this, m_image, "preview");
00381 UIUtilW::Assign(this, m_title, "title");
00382 UIUtilW::Assign(this, m_desc, "description");
00383 UIUtilW::Assign(this, m_url, "url");
00384 UIUtilW::Assign(this, m_author, "author");
00385
00386 if (err)
00387 {
00388 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditor'");
00389 return false;
00390 }
00391
00392 connect(m_sites, SIGNAL(itemClicked(MythUIButtonListItem*)),
00393 this, SLOT(slotEditSite(void)));
00394
00395 connect(m_delete, SIGNAL(Clicked(void)),
00396 SLOT(slotDeleteSite(void)));
00397 connect(m_edit, SIGNAL(Clicked(void)),
00398 SLOT(slotEditSite(void)));
00399 connect(m_new, SIGNAL(Clicked(void)),
00400 SLOT(slotNewSite(void)));
00401
00402 connect(m_sites, SIGNAL(itemSelected(MythUIButtonListItem *)),
00403 SLOT(slotItemChanged(void)));
00404
00405 BuildFocusList();
00406
00407 loadData();
00408
00409 if (m_sites->GetCount() == 0)
00410 SetFocusWidget(m_new);
00411 else
00412 slotItemChanged();
00413
00414 return true;
00415 }
00416
00417 void RSSEditor::loadData()
00418 {
00419 qDeleteAll(m_siteList);
00420 m_siteList = findAllDBRSS();
00421 fillRSSButtonList();
00422 if (m_sites->GetCount() == 0)
00423 {
00424 m_edit->SetVisible(false);
00425 m_delete->SetVisible(false);
00426 m_sites->SetVisible(false);
00427 }
00428 else
00429 {
00430 m_edit->SetVisible(true);
00431 m_delete->SetVisible(true);
00432 m_sites->SetVisible(true);
00433 }
00434 }
00435
00436 bool RSSEditor::keyPressEvent(QKeyEvent *event)
00437 {
00438 if (GetFocusWidget()->keyPressEvent(event))
00439 return true;
00440
00441 bool handled = false;
00442 QStringList actions;
00443 handled = GetMythMainWindow()->TranslateKeyPress("Internet Video", event, actions);
00444
00445 for (int i = 0; i < actions.size() && !handled; i++)
00446 {
00447 QString action = actions[i];
00448 handled = true;
00449
00450 if (action == "DELETE" && GetFocusWidget() == m_sites)
00451 {
00452 slotDeleteSite();
00453 }
00454 if (action == "EDIT" && GetFocusWidget() == m_sites)
00455 {
00456 slotEditSite();
00457 }
00458 else
00459 handled = false;
00460 }
00461
00462
00463 if (!handled && MythScreenType::keyPressEvent(event))
00464 handled = true;
00465
00466 return handled;
00467 }
00468
00469 void RSSEditor::fillRSSButtonList()
00470 {
00471 QMutexLocker locker(&m_lock);
00472
00473 m_sites->Reset();
00474
00475 for (RSSSite::rssList::iterator i = m_siteList.begin();
00476 i != m_siteList.end(); ++i)
00477 {
00478 MythUIButtonListItem *item =
00479 new MythUIButtonListItem(m_sites, (*i)->GetTitle());
00480 if (item)
00481 {
00482 item->SetText((*i)->GetTitle(), "title");
00483 item->SetText((*i)->GetDescription(), "description");
00484 item->SetText((*i)->GetURL(), "url");
00485 item->SetText((*i)->GetAuthor(), "author");
00486 item->SetData(qVariantFromValue(*i));
00487 item->SetImage((*i)->GetImage());
00488 }
00489 else
00490 delete item;
00491 }
00492 }
00493
00494 void RSSEditor::slotItemChanged()
00495 {
00496 RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
00497
00498 if (site)
00499 {
00500 if (m_image)
00501 {
00502 QString thumb = site->GetImage();
00503
00504 m_image->Reset();
00505
00506 if (!thumb.isEmpty())
00507 {
00508 m_image->SetFilename(site->GetImage());
00509 m_image->Load();
00510 }
00511 }
00512 if (m_title)
00513 m_title->SetText(site->GetTitle());
00514 if (m_desc)
00515 m_desc->SetText(site->GetDescription());
00516 if (m_url)
00517 m_url->SetText(site->GetURL());
00518 if (m_author)
00519 m_author->SetText(site->GetAuthor());
00520 }
00521 }
00522
00523 void RSSEditor::slotDeleteSite()
00524 {
00525 QMutexLocker locker(&m_lock);
00526
00527 QString message = tr("Are you sure you want to unsubscribe from this feed?");
00528
00529 MythScreenStack *m_popupStack = GetMythMainWindow()->GetStack("popup stack");
00530
00531 MythConfirmationDialog *confirmdialog =
00532 new MythConfirmationDialog(m_popupStack,message);
00533
00534 if (confirmdialog->Create())
00535 {
00536 m_popupStack->AddScreen(confirmdialog);
00537
00538 connect(confirmdialog, SIGNAL(haveResult(bool)),
00539 SLOT(doDeleteSite(bool)));
00540 }
00541 else
00542 delete confirmdialog;
00543 }
00544
00545 void RSSEditor::slotEditSite()
00546 {
00547 QMutexLocker locker(&m_lock);
00548
00549 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00550
00551 RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
00552
00553 if (site)
00554 {
00555 RSSEditPopup *rsseditpopup = new RSSEditPopup(site->GetURL(), true, mainStack, "rsseditpopup");
00556
00557 if (rsseditpopup->Create())
00558 {
00559 connect(rsseditpopup, SIGNAL(saving()), this,
00560 SLOT(listChanged()));
00561
00562 mainStack->AddScreen(rsseditpopup);
00563 }
00564 else
00565 {
00566 delete rsseditpopup;
00567 }
00568 }
00569 }
00570
00571 void RSSEditor::slotNewSite()
00572 {
00573 QMutexLocker locker(&m_lock);
00574
00575 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00576
00577 RSSEditPopup *rsseditpopup = new RSSEditPopup("", false, mainStack, "rsseditpopup");
00578
00579 if (rsseditpopup->Create())
00580 {
00581 connect(rsseditpopup, SIGNAL(saving()), this,
00582 SLOT(listChanged()));
00583
00584 mainStack->AddScreen(rsseditpopup);
00585 }
00586 else
00587 {
00588 delete rsseditpopup;
00589 }
00590 }
00591
00592 void RSSEditor::doDeleteSite(bool remove)
00593 {
00594 QMutexLocker locker(&m_lock);
00595
00596 if (!remove)
00597 return;
00598
00599 RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
00600
00601 if (removeFromDB(site))
00602 listChanged();
00603 }
00604
00605 void RSSEditor::listChanged()
00606 {
00607 m_changed = true;
00608 loadData();
00609 }