25 #include <tqdatetime.h>
27 #include <tqscrollview.h>
28 #include <tqvaluelist.h>
30 #include <tdeaction.h>
31 #include <tdeapplication.h>
33 #include <tdeglobalsettings.h>
34 #include <tdehtmlview.h>
35 #include <tdelocale.h>
38 #include <kstandarddirs.h>
40 #include <tdemessagebox.h>
41 #include <tdeio/netaccess.h>
42 #include <libtdepim/tdefileio.h>
44 #include "aboutdata.h"
45 #include "akregator_run.h"
46 #include "akregatorconfig.h"
47 #include "articleviewer.h"
52 #include "treenodevisitor.h"
59 static inline TQString directionOf(
const TQString &str)
61 return str.isRightToLeft() ?
"rtl" :
"ltr" ;
64 class ArticleViewer::ShowSummaryVisitor :
public TreeNodeVisitor
69 virtual ~ShowSummaryVisitor() {}
71 virtual bool visitFeed(Feed* node)
73 m_view->m_link = TQString();
76 text = TQString(
"<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ?
"rtl" :
"ltr");
78 text += TQString(
"<div class=\"headertitle\" dir=\"%1\">").arg(directionOf(Utils::stripTags(node->title())));
79 text += node->title();
80 if(node->unread() == 0)
81 text += i18n(
" (no unread articles)");
83 text += i18n(
" (1 unread article)",
" (%n unread articles)", node->unread());
87 if (!node->image().isNull())
89 text += TQString(
"<div class=\"body\">");
90 TQString url=node->xmlUrl();
91 TQString file = url.replace(
"/",
"_").replace(
":",
"_");
92 KURL u(m_view->m_imageDir);
94 text += TQString(
"<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(node->htmlUrl()).arg(u.url());
96 else text +=
"<div class=\"body\">";
99 if( !node->description().isEmpty() )
101 text += TQString(
"<div dir=\"%1\">").arg(Utils::stripTags(directionOf(node->description())));
102 text += i18n(
"<b>Description:</b> %1<br><br>").arg(node->description());
106 if ( !node->htmlUrl().isEmpty() )
108 text += TQString(
"<div dir=\"%1\">").arg(directionOf(node->htmlUrl()));
109 text += i18n(
"<b>Homepage:</b> <a href=\"%1\">%2</a>").arg(node->htmlUrl()).arg(node->htmlUrl());
116 m_view->renderContent(text);
120 virtual bool visitFolder(Folder* node)
122 m_view->m_link = TQString();
125 text = TQString(
"<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ?
"rtl" :
"ltr");
126 text += TQString(
"<div class=\"headertitle\" dir=\"%1\">%2").arg(directionOf(Utils::stripTags(node->title()))).arg(node->title());
127 if(node->unread() == 0)
128 text += i18n(
" (no unread articles)");
130 text += i18n(
" (1 unread article)",
" (%n unread articles)", node->unread());
131 text += TQString(
"</div>\n");
134 m_view->renderContent(text);
138 virtual bool visitTagNode(TagNode* node)
140 m_view->m_link = TQString();
143 text = TQString(
"<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ?
"rtl" :
"ltr");
144 text += TQString(
"<div class=\"headertitle\" dir=\"%1\">%2").arg(directionOf(Utils::stripTags(node->title()))).arg(node->title());
145 if(node->unread() == 0)
146 text += i18n(
" (no unread articles)");
148 text += i18n(
" (1 unread article)",
" (%n unread articles)", node->unread());
149 text += TQString(
"</div>\n");
152 m_view->renderContent(text);
162 : Viewer(parent, name), m_htmlFooter(), m_currentText(), m_node(0), m_viewMode(NormalView)
164 setJScriptEnabled(
false);
165 setJavaEnabled(
false);
166 setPluginsEnabled(
false);
168 m_showSummaryVisitor =
new ShowSummaryVisitor(
this);
169 setXMLFile(locate(
"data",
"akregator/articleviewer.rc"),
true);
173 new TDEAction( i18n(
"&Scroll Up"), TQString(),
"Up",
this, TQT_SLOT(slotScrollUp()), actionCollection(),
"articleviewer_scroll_up" );
174 new TDEAction( i18n(
"&Scroll Down"), TQString(),
"Down",
this, TQT_SLOT(slotScrollDown()), actionCollection(),
"articleviewer_scroll_down" );
176 connect(
this, TQT_SIGNAL(selectionChanged()),
this, TQT_SLOT(slotSelectionChanged()));
178 connect(kapp, TQT_SIGNAL(tdedisplayPaletteChanged()),
this, TQT_SLOT(slotPaletteOrFontChanged()) );
179 connect(kapp, TQT_SIGNAL(tdedisplayFontChanged()),
this, TQT_SLOT(slotPaletteOrFontChanged()) );
181 m_imageDir.setPath(TDEGlobal::dirs()->saveLocation(
"cache",
"akregator/Media/"));
182 m_htmlFooter =
"</body></html>";
185 ArticleViewer::~ArticleViewer()
187 delete m_showSummaryVisitor;
192 const TQColorGroup & cg = TQApplication::palette().active();
195 m_normalModeCSS = TQString(
196 "@media screen, print {"
198 " font-family: \"%1\" ! important;\n"
199 " font-size: %2 ! important;\n"
200 " color: %3 ! important;\n"
201 " background: %4 ! important;\n"
202 "}\n\n").arg(Settings::standardFont())
203 .arg(TQString::number(pointsToPixel(Settings::mediumFontSize()))+
"px")
204 .arg(cg.text().name())
205 .arg(cg.base().name());
206 m_normalModeCSS += TQString(
208 + TQString(
" color: %1 ! important;\n")
209 + TQString(!Settings::underlineLinks() ?
" text-decoration: none ! important;\n" :
"")
212 +
" background: %2 ! important;\n"
213 +
" color: %3 ! important;\n"
214 +
" border:1px solid #000;\n"
215 +
" margin-bottom: 10pt;\n"
218 .arg(cg.link().name())
219 .arg(cg.background().name())
220 .arg(cg.text().name());
222 m_normalModeCSS += TQString(
".headertitle a:link { color: %1 ! important; }\n"
223 ".headertitle a:visited { color: %2 ! important; }\n"
224 ".headertitle a:hover{ color: %3 ! important; }\n"
225 ".headertitle a:active { color: %4 ! important; }\n")
226 .arg(cg.highlightedText().name())
227 .arg(cg.highlightedText().name())
228 .arg(cg.highlightedText().name())
229 .arg(cg.highlightedText().name());
231 m_normalModeCSS += TQString(
233 " background: %1 ! important;\n"
235 " color: %2 ! important;\n"
236 " font-weight: bold;\n"
239 " font-weight: bold;\n"
241 " margin-right: 5px;\n"
247 " margin-left: 5px;\n"
248 "}\n\n").arg(cg.highlight().name())
249 .arg(cg.highlightedText().name());
251 m_normalModeCSS += TQString(
252 "body { clear: none; }\n\n"
255 " margin-bottom: 6px;\n"
258 ".content > P:first-child {\n margin-top: 1px; }\n"
259 ".content > DIV:first-child {\n margin-top: 1px; }\n"
260 ".content > BR:first-child {\n display: none; }\n"
261 "iframe {display: none !important; }\n"
262 "frame {display: none !important; }\n"
263 "frameset {display: none !important; }\n"
264 "object {display: none !important; }\n"
265 "applet {display: none !important; }\n"
271 const TQColorGroup & cg = TQApplication::palette().active();
274 m_combinedModeCSS = TQString (
276 "@media screen, print {"
278 " font-family: \"%1\" ! important;\n"
279 " font-size: %2 ! important;\n"
280 " color: %3 ! important;\n"
281 " background: %4 ! important;\n"
282 "}\n\n").arg(Settings::standardFont())
283 .arg(TQString::number(pointsToPixel(Settings::mediumFontSize()))+
"px")
284 .arg(cg.text().name())
285 .arg(cg.base().name());
286 m_combinedModeCSS += (
288 + TQString(
" color: %1 ! important;\n")
289 + TQString(!Settings::underlineLinks() ?
" text-decoration: none ! important;\n" :
"")
292 +
" background: %2 ! important;\n"
293 +
" color: %3 ! important;\n"
294 +
" border:1px solid #000;\n"
295 +
" margin-bottom: 10pt;\n"
298 .arg(cg.link().name())
299 .arg(cg.background().name())
300 .arg(cg.text().name());
302 m_combinedModeCSS += TQString(
".headertitle a:link { color: %1 ! important; }\n"
303 ".headertitle a:visited { color: %2 ! important; }\n"
304 ".headertitle a:hover{ color: %3 ! important; }\n"
305 ".headertitle a:active { color: %4 ! important; }\n")
306 .arg(cg.highlightedText().name())
307 .arg(cg.highlightedText().name())
308 .arg(cg.highlightedText().name())
309 .arg(cg.highlightedText().name());
310 m_combinedModeCSS += TQString(
312 " background: %1 ! important;\n"
314 " color: %2 ! important;\n"
315 " font-weight: bold;\n"
318 " font-weight: bold;\n"
320 " margin-right: 5px;\n"
326 " margin-left: 5px;\n"
327 "}\n\n").arg(cg.highlight().name())
328 .arg(cg.highlightedText().name());
330 m_combinedModeCSS += TQString(
331 "body { clear: none; }\n\n"
334 " margin-bottom: 6px;\n"
337 ".content > P:first-child {\n margin-top: 1px; }\n"
338 ".content > DIV:first-child {\n margin-top: 1px; }\n"
339 ".content > BR:first-child {\n display: none; }\n"
340 "iframe {display: none !important; }\n"
341 "frame {display: none !important; }\n"
342 "frameset {display: none !important; }\n"
343 "object {display: none !important; }\n"
344 "applet {display: none !important; }\n"
351 write(m_currentText);
355 bool ArticleViewer::openURL(
const KURL& url)
357 if (!m_article.isNull() && m_article.feed()->loadLinkedWebsite())
359 return Viewer::openURL(url);
368 void ArticleViewer::displayAboutPage()
370 TQString location = locate(
"data",
"akregator/about/main.html");
371 TQString content = KPIM::kFileToString(location);
372 content = content.arg( locate(
"data",
"libtdepim/about/kde_infopage.css" ) );
373 if ( kapp->reverseLayout() )
374 content = content.arg(
"@import \"%1\";" ).arg( locate(
"data",
"libtdepim/about/kde_infopage_rtl.css" ) );
376 content = content.arg(
"" );
378 begin(KURL( location ));
380 i18n(
"%1: Akregator version; %2: help:// URL; %3: homepage URL; "
381 "--- end of comment ---",
382 "<h2 style='margin-top: 0px;'>Welcome to Akregator %1</h2>"
383 "<p>Akregator is an RSS feed aggregator for the Trinity Desktop Environment. "
384 "Feed aggregators provide a convenient way to browse different kinds of "
385 "content, including news, blogs, and other content from online sites. "
386 "Instead of checking all your favorite web sites manually for updates, "
387 "Akregator collects the content for you.</p>"
388 "<p>For more information about using Akregator, check the "
389 "<a href=\"%3\">Akregator website</a>. If you do not want to see this page anymore, <a href=\"config:/disable_introduction\">click here</a>.</p>"
390 "<p>We hope that you will enjoy Akregator.</p>\n"
391 "<p>Thank you,</p>\n"
392 "<p style='margin-bottom: 0px'> The Akregator Team</p>\n")
393 .arg(AKREGATOR_VERSION)
394 .arg(
"http://akregator.kde.org/");
396 TQString fontSize = TQString::number( pointsToPixel( Settings::mediumFontSize() ));
397 TQString appTitle = i18n(
"Akregator");
398 TQString catchPhrase =
"";
399 TQString quickDescription = i18n(
"An RSS feed reader for the Trinity Desktop Environment.");
400 write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
407 text = TQString(
"<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ?
"rtl" :
"ltr");
409 if (!article.title().isEmpty())
411 text += TQString(
"<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
412 if (article.link().isValid())
413 text +=
"<a href=\""+article.link().url()+
"\">";
414 text += article.title().replace(
"<",
"<").replace(
">",
">");
415 if (article.link().isValid())
419 if (article.pubDate().isValid())
421 text += TQString(
"<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n(
"Date")));
422 text += TQString (
"%1:").arg(i18n(
"Date"));
423 text +=
"</span><span class=\"headertext\">";
424 text += TDEGlobal::locale()->formatDateTime(article.pubDate(),
false,
false)+
"</span>\n";
426 TQString author = article.author();
427 if (!author.isEmpty())
429 text += TQString(
"<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n(
"Author")));
430 text += TQString (
"%1:").arg(i18n(
"Author"));
431 text +=
"</span><span class=\"headertext\">";
432 text += author+
"</span>\n";
436 if (feed && !feed->
image().isNull())
438 TQString file = Utils::fileNameForUrl(feed->
xmlUrl());
441 text += TQString(
"<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->
htmlUrl()).arg(u.url());
446 if (!article.description().isEmpty())
448 text += TQString(
"<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
449 text +=
"<span class=\"content\">"+article.description()+
"</span>";
453 text +=
"<div class=\"body\">";
455 if (article.commentsLink().isValid())
457 text +=
"<a class=\"contentlink\" href=\"";
458 text += article.commentsLink().url();
459 text +=
"\">" + i18n(
"Comments");
460 if (article.comments())
462 text +=
" ("+ TQString::number(article.comments()) +
")";
467 if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
469 text +=
"<p><a class=\"contentlink\" href=\"";
471 if (article.link().isValid())
473 text += article.link().url();
477 text += article.guid();
479 text +=
"\">" + i18n(
"Complete Story" ) +
"</a></p>";
483 if (!article.enclosure().isNull())
500 text = TQString(
"<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ?
"rtl" :
"ltr");
502 KURL link = article.link();
504 if (!article.title().isEmpty())
506 text += TQString(
"<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
508 text +=
"<a href=\""+link.url()+
"\">";
509 text += article.title().replace(
"<",
"<").replace(
">",
">");
514 if (article.pubDate().isValid())
516 text += TQString(
"<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n(
"Date")));
517 text += TQString (
"%1:").arg(i18n(
"Date"));
518 text +=
"</span><span class=\"headertext\">";
519 text += TDEGlobal::locale()->formatDateTime(article.pubDate(),
false,
false)+
"</span>\n";
522 TQString author = article.author();
523 if (!author.isEmpty())
525 text += TQString(
"<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n(
"Author")));
526 text += TQString (
"%1:").arg(i18n(
"Author"));
527 text +=
"</span><span class=\"headertext\">";
528 text += author+
"</span>\n";
533 if (feed && !feed->
image().isNull())
535 TQString file = Utils::fileNameForUrl(feed->
xmlUrl());
538 text += TQString(
"<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->
htmlUrl()).arg(u.url());
543 if (!article.description().isEmpty())
545 text += TQString(
"<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
546 text +=
"<span class=\"content\">"+article.description()+
"</span>";
550 text +=
"<div class=\"body\">";
552 if (article.commentsLink().isValid())
554 text +=
"<a class=\"contentlink\" href=\"";
555 text += article.commentsLink().url();
556 text +=
"\">" + i18n(
"Comments");
557 if (article.comments())
559 text +=
" ("+ TQString::number(article.comments()) +
")";
564 if (link.isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
566 text +=
"<p><a class=\"contentlink\" href=\"";
574 text += article.guid();
576 text +=
"\">" + i18n(
"Complete Story" ) +
"</a></p>";
587 m_currentText = text;
596 TQString head = TQString(
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n <html><head><title>.</title></head>");
597 view()->setContentsPos(0,0);
599 setUserStyleSheet(m_viewMode == CombinedView ? m_combinedModeCSS : m_normalModeCSS);
610 void ArticleViewer::slotShowSummary(
TreeNode* node)
612 m_viewMode = SummaryView;
622 disconnectFromNode(m_node);
626 m_showSummaryVisitor->visit(node);
632 m_viewMode = NormalView;
633 disconnectFromNode(m_node);
636 m_link = article.link();
637 if (article.feed()->loadLinkedWebsite())
638 openURL(article.link());
645 if (m_statusFilter == statusFilter && m_textFilter == textFilter)
648 m_textFilter = textFilter;
649 m_statusFilter = statusFilter;
656 if (m_viewMode != CombinedView)
662 TQValueList<Article> articles = m_node->
articles();
664 TQValueList<Article>::ConstIterator end = articles.end();
665 TQValueList<Article>::ConstIterator it = articles.begin();
673 for ( ; it != end; ++it)
675 if ( !(*it).isDeleted() && m_textFilter.matches(*it) && m_statusFilter.matches(*it) )
688 void ArticleViewer::slotArticlesUpdated(
TreeNode* ,
const TQValueList<Article>& )
690 if (m_viewMode == CombinedView)
694 void ArticleViewer::slotArticlesAdded(TreeNode* ,
const TQValueList<Article>& )
698 void ArticleViewer::slotArticlesRemoved(TreeNode* ,
const TQValueList<Article>& )
712 disconnectFromNode(m_node);
721 m_viewMode = CombinedView;
724 disconnectFromNode(m_node);
731 if (node && !node->
articles().isEmpty())
732 m_link = node->
articles().first().link();
739 void ArticleViewer::keyPressEvent(TQKeyEvent* e)
744 void ArticleViewer::urlSelected(
const TQString &url,
int button,
int state,
const TQString& _target, KParts::URLArgs args)
746 if(url ==
"config:/disable_introduction") {
747 if(KMessageBox::questionYesNo( widget(), i18n(
"Are you sure you want to disable this introduction page?"), i18n(
"Disable Introduction Page"), i18n(
"Disable"), i18n(
"Keep Enabled") ) == KMessageBox::Yes) {
748 TDEConfig *conf = Settings::self()->config();
749 conf->setGroup(
"General");
750 conf->writeEntry(
"Disable Introduction",
"true");
754 Viewer::urlSelected(url, button, state, _target, args);
757 void ArticleViewer::slotPaletteOrFontChanged()
764 void ArticleViewer::connectToNode(TreeNode* node)
768 if (m_viewMode == CombinedView)
771 connect( node, TQT_SIGNAL(signalArticlesAdded(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesAdded(TreeNode*,
const TQValueList<Article>&)));
772 connect( node, TQT_SIGNAL(signalArticlesRemoved(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesRemoved(TreeNode*,
const TQValueList<Article>&)));
773 connect( node, TQT_SIGNAL(signalArticlesUpdated(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesUpdated(TreeNode*,
const TQValueList<Article>&)));
775 if (m_viewMode == SummaryView)
776 connect( node, TQT_SIGNAL(signalChanged(TreeNode*)),
this, TQT_SLOT(slotShowSummary(TreeNode*) ) );
778 connect( node, TQT_SIGNAL(signalDestroyed(TreeNode*)),
this, TQT_SLOT(
slotClear() ) );
782 void ArticleViewer::disconnectFromNode(TreeNode* node)
787 disconnect( node, TQT_SIGNAL(signalDestroyed(TreeNode*)),
this, TQT_SLOT(
slotClear() ) );
788 disconnect( node, TQT_SIGNAL(signalChanged(TreeNode*)),
this, TQT_SLOT(slotShowSummary(TreeNode*) ) );
789 disconnect( node, TQT_SIGNAL(signalArticlesAdded(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesAdded(TreeNode*,
const TQValueList<Article>&)));
790 disconnect( node, TQT_SIGNAL(signalArticlesRemoved(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesRemoved(TreeNode*,
const TQValueList<Article>&)));
791 disconnect( node, TQT_SIGNAL(signalArticlesUpdated(TreeNode*,
const TQValueList<Article>&)),
this, TQT_SLOT(slotArticlesUpdated(TreeNode*,
const TQValueList<Article>&)));
797 #include "articleviewer.moc"