MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
rsseditor.cpp
Go to the documentation of this file.
1 #include <QDomDocument>
2 #include <QDateTime>
3 #include <QImageReader>
4 
5 // MythTV headers
6 #include <mythuibutton.h>
7 #include <mythuibuttonlist.h>
8 #include <mythuitextedit.h>
9 #include <mythuicheckbox.h>
10 #include <mythuifilebrowser.h>
11 #include <mythmainwindow.h>
12 #include <mythdialogbox.h>
13 #include <mythdate.h>
14 #include <mythcontext.h>
15 #include <mythdbcon.h>
16 #include <httpcomms.h>
17 #include <mythdirs.h>
18 #include <netutils.h>
19 #include <rssparse.h>
20 
21 // RSS headers
22 #include "rsseditor.h"
23 
24 #define LOC QString("RSSEditor: ")
25 #define LOC_WARN QString("RSSEditor, Warning: ")
26 #define LOC_ERR QString("RSSEditor, Error: ")
27 
28 namespace
29 {
30  const QString CEID_NEWIMAGE = "image";
31 
32  QStringList GetSupportedImageExtensionFilter()
33  {
34  QStringList ret;
35 
36  QList<QByteArray> exts = QImageReader::supportedImageFormats();
37  for (QList<QByteArray>::iterator p = exts.begin(); p != exts.end(); ++p)
38  {
39  ret.append(QString("*.").append(*p));
40  }
41 
42  return ret;
43  }
44 }
45 
51  const QString &url, bool edit,
52  MythScreenStack *parent, const QString &name) :
53  MythScreenType(parent, name),
54  m_site(NULL),
55  m_urlText(url), m_editing(edit),
56  m_thumbImage(NULL), m_thumbButton(NULL),
57  m_urlEdit(NULL), m_titleEdit(NULL),
58  m_descEdit(NULL), m_authorEdit(NULL),
59  m_okButton(NULL), m_cancelButton(NULL),
60  m_download(NULL), m_manager(NULL),
61  m_reply(NULL)
62 {
63 }
64 
66 {
67  if (m_manager)
68  {
69  m_manager->disconnect();
70  m_manager->deleteLater();
71  m_manager = NULL;
72  }
73 }
74 
76 {
77  // Load the theme for this screen
78  bool foundtheme = LoadWindowFromXML("netvision-ui.xml", "rsseditpopup", this);
79 
80  if (!foundtheme)
81  return false;
82 
83  bool err = false;
84  UIUtilE::Assign(this, m_urlEdit, "url", &err);
85  UIUtilE::Assign(this, m_titleEdit, "title", &err);
86  UIUtilE::Assign(this, m_descEdit, "description", &err);
87  UIUtilE::Assign(this, m_authorEdit, "author", &err);
88  UIUtilE::Assign(this, m_download, "download", &err);
89  UIUtilE::Assign(this, m_okButton, "ok", &err);
90  UIUtilE::Assign(this, m_cancelButton, "cancel", &err);
91  UIUtilE::Assign(this, m_thumbButton, "preview_browse", &err);
92  UIUtilE::Assign(this, m_thumbImage, "preview", &err);
93 
94  if (err)
95  {
96  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditpopup'");
97  return false;
98  }
99 
100  connect(m_okButton, SIGNAL(Clicked()), this, SLOT(parseAndSave()));
101  connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
102  connect(m_thumbButton, SIGNAL(Clicked()), this, SLOT(doFileBrowser()));
103 
108 
109  if (m_editing)
110  {
112 
117 
118  QString thumb = m_site->GetImage();
119  if (!thumb.isEmpty())
120  {
121  m_thumbImage->SetFilename(thumb);
122  m_thumbImage->Load();
123  }
124 
125  if (m_site->GetDownload() == 1)
127  }
128 
129  BuildFocusList();
130 
131  return true;
132 }
133 
134 bool RSSEditPopup::keyPressEvent(QKeyEvent *event)
135 {
136  if (GetFocusWidget()->keyPressEvent(event))
137  return true;
138 
139  bool handled = false;
140  QStringList actions;
141  handled = GetMythMainWindow()->TranslateKeyPress("Internet Video", event, actions);
142 
143  if (!handled && MythScreenType::keyPressEvent(event))
144  handled = true;
145 
146  return handled;
147 }
148 
150 {
151  if (m_editing)
152  {
153  QString title = m_titleEdit->GetText();
154  QString desc = m_descEdit->GetText();
155  QString author = m_authorEdit->GetText();
156  QString link = m_urlEdit->GetText();
157  QString filename = m_thumbImage->GetFilename();
158 
159  bool download;
161  download = true;
162  else
163  download = false;
164 
166 
167  if (insertInDB(new RSSSite(title, filename, VIDEO_PODCAST,
168  desc, link, author, download, MythDate::current())))
169  emit saving();
170  Close();
171  }
172  else
173  {
174  m_manager = new QNetworkAccessManager();
175  QUrl qurl(m_urlEdit->GetText());
176 
177  m_reply = m_manager->get(QNetworkRequest(qurl));
178 
179  connect(m_manager, SIGNAL(finished(QNetworkReply*)), this,
180  SLOT(slotCheckRedirect(QNetworkReply*)));
181  }
182 }
183 
184 QUrl RSSEditPopup::redirectUrl(const QUrl& possibleRedirectUrl,
185  const QUrl& oldRedirectUrl) const
186 {
187  QUrl redirectUrl;
188  if(!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != oldRedirectUrl)
189  redirectUrl = possibleRedirectUrl;
190  return redirectUrl;
191 }
192 
193 void RSSEditPopup::slotCheckRedirect(QNetworkReply* reply)
194 {
195  QVariant possibleRedirectUrl =
196  reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
197 
198  QUrl urlRedirectedTo;
199  urlRedirectedTo = redirectUrl(
200  possibleRedirectUrl.toUrl(), urlRedirectedTo);
201 
202  if(!urlRedirectedTo.isEmpty())
203  {
204  m_urlEdit->SetText(urlRedirectedTo.toString());
205  m_manager->get(QNetworkRequest(urlRedirectedTo));
206  }
207  else
208  {
209 // urlRedirectedTo.clear();
210  slotSave(reply);
211  }
212  reply->deleteLater();
213 }
214 
215 void RSSEditPopup::slotSave(QNetworkReply* reply)
216 {
217  QDomDocument document;
218  document.setContent(reply->read(reply->bytesAvailable()), true);
219 
220  QString text = document.toString();
221 
222  QString title = m_titleEdit->GetText();
223  QString description = m_descEdit->GetText();
224  QString author = m_authorEdit->GetText();
225  QString file = m_thumbImage->GetFilename();
226 
227  LOG(VB_GENERAL, LOG_DEBUG, QString("Text to Parse: %1").arg(text));
228 
229  QDomElement root = document.documentElement();
230  QDomElement channel = root.firstChildElement ("channel");
231  if (!channel.isNull ())
232  {
233  Parse parser;
234  if (title.isEmpty())
235  title = channel.firstChildElement("title").text().trimmed();
236  if (description.isEmpty())
237  description = channel.firstChildElement("description").text();
238  if (author.isEmpty())
239  author = parser.GetAuthor(channel);
240  if (author.isEmpty())
241  author = channel.firstChildElement("managingEditor").text();
242  if (author.isEmpty())
243  author = channel.firstChildElement("webMaster").text();
244 
245  QString thumbnailURL = channel.firstChildElement("image").attribute("url");
246  if (thumbnailURL.isEmpty())
247  {
248  QDomElement thumbElem = channel.firstChildElement("image");
249  if (!thumbElem.isNull())
250  thumbnailURL = thumbElem.firstChildElement("url").text();
251  }
252  if (thumbnailURL.isEmpty())
253  {
254  QDomNodeList nodes = channel.elementsByTagNameNS(
255  "http://www.itunes.com/dtds/podcast-1.0.dtd", "image");
256  if (nodes.size())
257  {
258  thumbnailURL = nodes.at(0).toElement().attributeNode("href").value();
259  if (thumbnailURL.isEmpty())
260  thumbnailURL = nodes.at(0).toElement().text();
261  }
262  }
263 
264  bool download;
266  download = true;
267  else
268  download = false;
269 
270  QDateTime updated = MythDate::current();
271  QString filename("");
272 
273  if (file.isEmpty())
274  filename = file;
275 
276  QString link = m_urlEdit->GetText();
277 
278  if (!thumbnailURL.isEmpty() && filename.isEmpty())
279  {
280  QString fileprefix = GetConfDir();
281 
282  QDir dir(fileprefix);
283  if (!dir.exists())
284  dir.mkdir(fileprefix);
285 
286  fileprefix += "/MythNetvision";
287 
288  dir = QDir(fileprefix);
289  if (!dir.exists())
290  dir.mkdir(fileprefix);
291 
292  fileprefix += "/sitecovers";
293 
294  dir = QDir(fileprefix);
295  if (!dir.exists())
296  dir.mkdir(fileprefix);
297 
298  QFileInfo fi(thumbnailURL);
299  QString rawFilename = fi.fileName();
300 
301  filename = QString("%1/%2").arg(fileprefix).arg(rawFilename);
302 
303  bool exists = QFile::exists(filename);
304  if (!exists)
305  HttpComms::getHttpFile(filename, thumbnailURL, 20000, 1, 2);
306  }
307  if (insertInDB(new RSSSite(title, filename, VIDEO_PODCAST, description, link,
308  author, download, MythDate::current())))
309  emit saving();
310  }
311  Close();
312 }
313 
315 {
316  SelectImagePopup(GetConfDir() + "/MythNetvision" + "/sitecovers", *this, CEID_NEWIMAGE);
317 }
318 
320  QObject &inst, const QString &returnEvent)
321 {
322  MythScreenStack *popupStack =
323  GetMythMainWindow()->GetStack("popup stack");
324 
325  MythUIFileBrowser *fb = new MythUIFileBrowser(popupStack, prefix);
326  fb->SetNameFilter(GetSupportedImageExtensionFilter());
327  if (fb->Create())
328  {
329  fb->SetReturnEvent(&inst, returnEvent);
330  popupStack->AddScreen(fb);
331  }
332  else
333  delete fb;
334 }
335 
336 void RSSEditPopup::customEvent(QEvent *levent)
337 {
338  if (levent->type() == DialogCompletionEvent::kEventType)
339  {
341  if (dce->GetId() == CEID_NEWIMAGE)
342  {
344  m_thumbImage->Load();
345  m_thumbImage->Show();
346  }
347  }
348 }
349 
350 RSSEditor::RSSEditor(MythScreenStack *parent, const QString &name) :
351  MythScreenType(parent, name), m_lock(QMutex::Recursive),
352  m_changed(false), m_sites(NULL), m_new(NULL), m_delete(NULL), m_edit(NULL),
353  m_image(NULL), m_title(NULL), m_url(NULL), m_desc(NULL), m_author(NULL)
354 {
355 }
356 
358 {
359  QMutexLocker locker(&m_lock);
360 
361  if (m_changed)
362  emit itemsChanged();
363 }
364 
366 {
367  QMutexLocker locker(&m_lock);
368 
369  // Load the theme for this screen
370  bool foundtheme = LoadWindowFromXML("netvision-ui.xml", "rsseditor", this);
371 
372  if (!foundtheme)
373  return false;
374 
375  bool err = false;
376  UIUtilE::Assign(this, m_sites, "sites", &err);
377  UIUtilE::Assign(this, m_new, "new", &err);
378  UIUtilE::Assign(this, m_delete, "delete", &err);
379  UIUtilE::Assign(this, m_edit, "edit", &err);
380 
381  UIUtilW::Assign(this, m_image, "preview");
382  UIUtilW::Assign(this, m_title, "title");
383  UIUtilW::Assign(this, m_desc, "description");
384  UIUtilW::Assign(this, m_url, "url");
385  UIUtilW::Assign(this, m_author, "author");
386 
387  if (err)
388  {
389  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditor'");
390  return false;
391  }
392 
393  connect(m_sites, SIGNAL(itemClicked(MythUIButtonListItem*)),
394  this, SLOT(slotEditSite(void)));
395 
396  connect(m_delete, SIGNAL(Clicked(void)),
397  SLOT(slotDeleteSite(void)));
398  connect(m_edit, SIGNAL(Clicked(void)),
399  SLOT(slotEditSite(void)));
400  connect(m_new, SIGNAL(Clicked(void)),
401  SLOT(slotNewSite(void)));
402 
403  connect(m_sites, SIGNAL(itemSelected(MythUIButtonListItem *)),
404  SLOT(slotItemChanged(void)));
405 
406  BuildFocusList();
407 
408  loadData();
409 
410  if (m_sites->GetCount() == 0)
412  else
413  slotItemChanged();
414 
415  return true;
416 }
417 
419 {
420  qDeleteAll(m_siteList);
423  if (m_sites->GetCount() == 0)
424  {
425  m_edit->SetVisible(false);
426  m_delete->SetVisible(false);
427  m_sites->SetVisible(false);
428  }
429  else
430  {
431  m_edit->SetVisible(true);
432  m_delete->SetVisible(true);
433  m_sites->SetVisible(true);
434  }
435 }
436 
437 bool RSSEditor::keyPressEvent(QKeyEvent *event)
438 {
439  if (GetFocusWidget()->keyPressEvent(event))
440  return true;
441 
442  bool handled = false;
443  QStringList actions;
444  handled = GetMythMainWindow()->TranslateKeyPress("Internet Video", event, actions);
445 
446  for (int i = 0; i < actions.size() && !handled; i++)
447  {
448  QString action = actions[i];
449  handled = true;
450 
451  if (action == "DELETE" && GetFocusWidget() == m_sites)
452  {
453  slotDeleteSite();
454  }
455  if (action == "EDIT" && GetFocusWidget() == m_sites)
456  {
457  slotEditSite();
458  }
459  else
460  handled = false;
461  }
462 
463 
464  if (!handled && MythScreenType::keyPressEvent(event))
465  handled = true;
466 
467  return handled;
468 }
469 
471 {
472  QMutexLocker locker(&m_lock);
473 
474  m_sites->Reset();
475 
476  for (RSSSite::rssList::iterator i = m_siteList.begin();
477  i != m_siteList.end(); ++i)
478  {
479  MythUIButtonListItem *item =
480  new MythUIButtonListItem(m_sites, (*i)->GetTitle());
481  if (item)
482  {
483  item->SetText((*i)->GetTitle(), "title");
484  item->SetText((*i)->GetDescription(), "description");
485  item->SetText((*i)->GetURL(), "url");
486  item->SetText((*i)->GetAuthor(), "author");
487  item->SetData(qVariantFromValue(*i));
488  item->SetImage((*i)->GetImage());
489  }
490  else
491  delete item;
492  }
493 }
494 
496 {
497  RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
498 
499  if (site)
500  {
501  if (m_image)
502  {
503  QString thumb = site->GetImage();
504 
505  m_image->Reset();
506 
507  if (!thumb.isEmpty())
508  {
509  m_image->SetFilename(site->GetImage());
510  m_image->Load();
511  }
512  }
513  if (m_title)
514  m_title->SetText(site->GetTitle());
515  if (m_desc)
516  m_desc->SetText(site->GetDescription());
517  if (m_url)
518  m_url->SetText(site->GetURL());
519  if (m_author)
520  m_author->SetText(site->GetAuthor());
521  }
522 }
523 
525 {
526  QMutexLocker locker(&m_lock);
527 
528  QString message = tr("Are you sure you want to unsubscribe from this feed?");
529 
530  MythScreenStack *m_popupStack = GetMythMainWindow()->GetStack("popup stack");
531 
532  MythConfirmationDialog *confirmdialog =
533  new MythConfirmationDialog(m_popupStack,message);
534 
535  if (confirmdialog->Create())
536  {
537  m_popupStack->AddScreen(confirmdialog);
538 
539  connect(confirmdialog, SIGNAL(haveResult(bool)),
540  SLOT(doDeleteSite(bool)));
541  }
542  else
543  delete confirmdialog;
544 }
545 
547 {
548  QMutexLocker locker(&m_lock);
549 
551 
552  RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
553 
554  if (site)
555  {
556  RSSEditPopup *rsseditpopup = new RSSEditPopup(site->GetURL(), true, mainStack, "rsseditpopup");
557 
558  if (rsseditpopup->Create())
559  {
560  connect(rsseditpopup, SIGNAL(saving()), this,
561  SLOT(listChanged()));
562 
563  mainStack->AddScreen(rsseditpopup);
564  }
565  else
566  {
567  delete rsseditpopup;
568  }
569  }
570 }
571 
573 {
574  QMutexLocker locker(&m_lock);
575 
577 
578  RSSEditPopup *rsseditpopup = new RSSEditPopup("", false, mainStack, "rsseditpopup");
579 
580  if (rsseditpopup->Create())
581  {
582  connect(rsseditpopup, SIGNAL(saving()), this,
583  SLOT(listChanged()));
584 
585  mainStack->AddScreen(rsseditpopup);
586  }
587  else
588  {
589  delete rsseditpopup;
590  }
591 }
592 
593 void RSSEditor::doDeleteSite(bool remove)
594 {
595  QMutexLocker locker(&m_lock);
596 
597  if (!remove)
598  return;
599 
600  RSSSite *site = qVariantValue<RSSSite *>(m_sites->GetItemCurrent()->GetData());
601 
602  if (removeFromDB(site))
603  listChanged();
604 }
605 
607 {
608  m_changed = true;
609  loadData();
610 }