MythTV  0.26-pre
rsseditor.cpp
Go to the documentation of this file.
00001 #include <QDomDocument>
00002 #include <QDateTime>
00003 #include <QImageReader>
00004 
00005 // MythTV headers
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 // RSS headers
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     // Load the theme for this screen
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 //        urlRedirectedTo.clear();
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     // Load the theme for this screen
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends