00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qdatetime.h>
00026 #include <qevent.h>
00027 #include <qscrollview.h>
00028 #include <qvaluelist.h>
00029
00030 #include <kaction.h>
00031 #include <kapplication.h>
00032 #include <kdebug.h>
00033 #include <kglobalsettings.h>
00034 #include <khtmlview.h>
00035 #include <klocale.h>
00036 #include <kprocess.h>
00037 #include <krun.h>
00038 #include <kstandarddirs.h>
00039 #include <kshell.h>
00040 #include <kmessagebox.h>
00041 #include <kio/netaccess.h>
00042 #include <libkdepim/kfileio.h>
00043
00044 #include "aboutdata.h"
00045 #include "akregator_run.h"
00046 #include "akregatorconfig.h"
00047 #include "articleviewer.h"
00048 #include "feed.h"
00049 #include "folder.h"
00050 #include "article.h"
00051 #include "treenode.h"
00052 #include "treenodevisitor.h"
00053 #include "tagnode.h"
00054 #include "utils.h"
00055
00056 namespace Akregator {
00057
00058
00059 static inline QString directionOf(const QString &str)
00060 {
00061 return str.isRightToLeft() ? "rtl" : "ltr" ;
00062 }
00063
00064 class ArticleViewer::ShowSummaryVisitor : public TreeNodeVisitor
00065 {
00066 public:
00067
00068 ShowSummaryVisitor(ArticleViewer* view) : m_view(view) {}
00069
00070 virtual bool visitFeed(Feed* node)
00071 {
00072 m_view->m_link = QString();
00073
00074 QString text;
00075 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::reverseLayout() ? "rtl" : "ltr");
00076
00077 text += QString("<div class=\"headertitle\" dir=\"%1\">").arg(directionOf(Utils::stripTags(node->title())));
00078 text += node->title();
00079 if(node->unread() == 0)
00080 text += i18n(" (no unread articles)");
00081 else
00082 text += i18n(" (1 unread article)", " (%n unread articles)", node->unread());
00083 text += "</div>\n";
00084 text += "</div>\n";
00085
00086 if (!node->image().isNull())
00087 {
00088 text += QString("<div class=\"body\">");
00089 QString url=node->xmlUrl();
00090 QString file = url.replace("/", "_").replace(":", "_");
00091 KURL u(m_view->m_imageDir);
00092 u.setFileName(file);
00093 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(node->htmlUrl()).arg(u.url());
00094 }
00095 else text += "<div class=\"body\">";
00096
00097
00098 if( !node->description().isEmpty() )
00099 {
00100 text += QString("<div dir=\"%1\">").arg(Utils::stripTags(directionOf(node->description())));
00101 text += i18n("<b>Description:</b> %1<br><br>").arg(node->description());
00102 text += "</div>\n";
00103 }
00104
00105 if ( !node->htmlUrl().isEmpty() )
00106 {
00107 text += QString("<div dir=\"%1\">").arg(directionOf(node->htmlUrl()));
00108 text += i18n("<b>Homepage:</b> <a href=\"%1\">%2</a>").arg(node->htmlUrl()).arg(node->htmlUrl());
00109 text += "</div>\n";
00110 }
00111
00112
00113 text += "</div>";
00114
00115 m_view->renderContent(text);
00116 return true;
00117 }
00118
00119 virtual bool visitFolder(Folder* node)
00120 {
00121 m_view->m_link = QString();
00122
00123 QString text;
00124 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::reverseLayout() ? "rtl" : "ltr");
00125 text += QString("<div class=\"headertitle\" dir=\"%1\">%2").arg(directionOf(Utils::stripTags(node->title()))).arg(node->title());
00126 if(node->unread() == 0)
00127 text += i18n(" (no unread articles)");
00128 else
00129 text += i18n(" (1 unread article)", " (%n unread articles)", node->unread());
00130 text += QString("</div>\n");
00131 text += "</div>\n";
00132
00133 m_view->renderContent(text);
00134 return true;
00135 }
00136
00137 virtual bool visitTagNode(TagNode* node)
00138 {
00139 m_view->m_link = QString();
00140
00141 QString text;
00142 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::reverseLayout() ? "rtl" : "ltr");
00143 text += QString("<div class=\"headertitle\" dir=\"%1\">%2").arg(directionOf(Utils::stripTags(node->title()))).arg(node->title());
00144 if(node->unread() == 0)
00145 text += i18n(" (no unread articles)");
00146 else
00147 text += i18n(" (1 unread article)", " (%n unread articles)", node->unread());
00148 text += QString("</div>\n");
00149 text += "</div>\n";
00150
00151 m_view->renderContent(text);
00152 return true;
00153 }
00154
00155 private:
00156
00157 ArticleViewer* m_view;
00158 };
00159
00160 ArticleViewer::ArticleViewer(QWidget *parent, const char *name)
00161 : Viewer(parent, name), m_htmlFooter(), m_currentText(), m_node(0), m_viewMode(NormalView)
00162 {
00163 m_showSummaryVisitor = new ShowSummaryVisitor(this);
00164 setXMLFile(locate("data", "akregator/articleviewer.rc"), true);
00165
00166 generateNormalModeCSS();
00167 generateCombinedModeCSS();
00168 new KAction( i18n("&Scroll Up"), QString::null, "Up", this, SLOT(slotScrollUp()), actionCollection(), "articleviewer_scroll_up" );
00169 new KAction( i18n("&Scroll Down"), QString::null, "Down", this, SLOT(slotScrollDown()), actionCollection(), "articleviewer_scroll_down" );
00170
00171 connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
00172
00173 connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteOrFontChanged()) );
00174 connect(kapp, SIGNAL(kdisplayFontChanged()), this, SLOT(slotPaletteOrFontChanged()) );
00175
00176 m_imageDir.setPath(KGlobal::dirs()->saveLocation("cache", "akregator/Media/"));
00177 m_htmlFooter = "</body></html>";
00178 }
00179
00180 ArticleViewer::~ArticleViewer()
00181 {
00182 delete m_showSummaryVisitor;
00183 }
00184
00185 void ArticleViewer::generateNormalModeCSS()
00186 {
00187 const QColorGroup & cg = QApplication::palette().active();
00188
00189
00190 m_normalModeCSS = QString(
00191 "@media screen, print {"
00192 "body {\n"
00193 " font-family: \"%1\" ! important;\n"
00194 " font-size: %2 ! important;\n"
00195 " color: %3 ! important;\n"
00196 " background: %4 ! important;\n"
00197 "}\n\n").arg(Settings::standardFont())
00198 .arg(QString::number(pointsToPixel(Settings::mediumFontSize()))+"px")
00199 .arg(cg.text().name())
00200 .arg(cg.base().name());
00201 m_normalModeCSS += QString(
00202 "a {\n"
00203 + QString(" color: %1 ! important;\n")
00204 + QString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00205 + "}\n\n"
00206 +".headerbox {\n"
00207 +" background: %2 ! important;\n"
00208 +" color: %3 ! important;\n"
00209 +" border:1px solid #000;\n"
00210 +" margin-bottom: 10pt;\n"
00211
00212 + "}\n\n")
00213 .arg(cg.link().name())
00214 .arg(cg.background().name())
00215 .arg(cg.text().name());
00216
00217 m_normalModeCSS += QString(".headertitle a:link { color: %1 ! important; }\n"
00218 ".headertitle a:visited { color: %2 ! important; }\n"
00219 ".headertitle a:hover{ color: %3 ! important; }\n"
00220 ".headertitle a:active { color: %4 ! important; }\n")
00221 .arg(cg.highlightedText().name())
00222 .arg(cg.highlightedText().name())
00223 .arg(cg.highlightedText().name())
00224 .arg(cg.highlightedText().name());
00225
00226 m_normalModeCSS += QString(
00227 ".headertitle {\n"
00228 " background: %1 ! important;\n"
00229 " padding:2px;\n"
00230 " color: %2 ! important;\n"
00231 " font-weight: bold;\n"
00232 "}\n\n"
00233 ".header {\n"
00234 " font-weight: bold;\n"
00235 " padding:2px;\n"
00236 " margin-right: 5px;\n"
00237 "}\n\n"
00238 ".headertext {\n"
00239 "}\n\n"
00240 ".headimage {\n"
00241 " float: right;\n"
00242 " margin-left: 5px;\n"
00243 "}\n\n").arg(cg.highlight().name())
00244 .arg(cg.highlightedText().name());
00245
00246 m_normalModeCSS += QString(
00247 "body { clear: none; }\n\n"
00248 ".content {\n"
00249 " display: block;\n"
00250 " margin-bottom: 6px;\n"
00251 "}\n\n"
00252
00253 ".content > P:first-child {\n margin-top: 1px; }\n"
00254 ".content > DIV:first-child {\n margin-top: 1px; }\n"
00255 ".content > BR:first-child {\n display: none; }\n"
00256 "iframe {display: none !important; }\n"
00257 "frame {display: none !important; }\n"
00258 "frameset {display: none !important; }\n"
00259 "object {display: none !important; }\n"
00260 "applet {display: none !important; }\n"
00261 "}\n\n");
00262 }
00263
00264 void ArticleViewer::generateCombinedModeCSS()
00265 {
00266 const QColorGroup & cg = QApplication::palette().active();
00267
00268
00269 m_combinedModeCSS = QString (
00270
00271 "@media screen, print {"
00272 "body {\n"
00273 " font-family: \"%1\" ! important;\n"
00274 " font-size: %2 ! important;\n"
00275 " color: %3 ! important;\n"
00276 " background: %4 ! important;\n"
00277 "}\n\n").arg(Settings::standardFont())
00278 .arg(QString::number(pointsToPixel(Settings::mediumFontSize()))+"px")
00279 .arg(cg.text().name())
00280 .arg(cg.base().name());
00281 m_combinedModeCSS += (
00282 "a {\n"
00283 + QString(" color: %1 ! important;\n")
00284 + QString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00285 + "}\n\n"
00286 +".headerbox {\n"
00287 +" background: %2 ! important;\n"
00288 +" color: %3 ! important;\n"
00289 +" border:1px solid #000;\n"
00290 +" margin-bottom: 10pt;\n"
00291
00292 + "}\n\n")
00293 .arg(cg.link().name())
00294 .arg(cg.background().name())
00295 .arg(cg.text().name());
00296
00297 m_combinedModeCSS += QString(".headertitle a:link { color: %1 ! important; }\n"
00298 ".headertitle a:visited { color: %2 ! important; }\n"
00299 ".headertitle a:hover{ color: %3 ! important; }\n"
00300 ".headertitle a:active { color: %4 ! important; }\n")
00301 .arg(cg.highlightedText().name())
00302 .arg(cg.highlightedText().name())
00303 .arg(cg.highlightedText().name())
00304 .arg(cg.highlightedText().name());
00305 m_combinedModeCSS += QString(
00306 ".headertitle {\n"
00307 " background: %1 ! important;\n"
00308 " padding:2px;\n"
00309 " color: %2 ! important;\n"
00310 " font-weight: bold;\n"
00311 "}\n\n"
00312 ".header {\n"
00313 " font-weight: bold;\n"
00314 " padding:2px;\n"
00315 " margin-right: 5px;\n"
00316 "}\n\n"
00317 ".headertext {\n"
00318 "}\n\n"
00319 ".headimage {\n"
00320 " float: right;\n"
00321 " margin-left: 5px;\n"
00322 "}\n\n").arg(cg.highlight().name())
00323 .arg(cg.highlightedText().name());
00324
00325 m_combinedModeCSS += QString(
00326 "body { clear: none; }\n\n"
00327 ".content {\n"
00328 " display: block;\n"
00329 " margin-bottom: 6px;\n"
00330 "}\n\n"
00331
00332 ".content > P:first-child {\n margin-top: 1px; }\n"
00333 ".content > DIV:first-child {\n margin-top: 1px; }\n"
00334 ".content > BR:first-child {\n display: none; }\n"
00335 "iframe {display: none !important; }\n"
00336 "frame {display: none !important; }\n"
00337 "frameset {display: none !important; }\n"
00338 "object {display: none !important; }\n"
00339 "applet {display: none !important; }\n"
00340 "}\n\n");
00341 }
00342
00343 void ArticleViewer::reload()
00344 {
00345 beginWriting();
00346 write(m_currentText);
00347 endWriting();
00348 }
00349
00350 bool ArticleViewer::openURL(const KURL& url)
00351 {
00352 if (!m_article.isNull() && m_article.feed()->loadLinkedWebsite())
00353 {
00354 return Viewer::openURL(url);
00355 }
00356 else
00357 {
00358 reload();
00359 return true;
00360 }
00361 }
00362
00363 void ArticleViewer::displayAboutPage()
00364 {
00365 QString location = locate("data", "akregator/about/main.html");
00366 QString content = KPIM::kFileToString(location);
00367 content = content.arg( locate( "data", "libkdepim/about/kde_infopage.css" ) );
00368 if ( kapp->reverseLayout() )
00369 content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libkdepim/about/kde_infopage_rtl.css" ) );
00370 else
00371 content = content.arg( "" );
00372
00373 begin(KURL( location ));
00374 QString info =
00375 i18n("%1: Akregator version; %2: help:// URL; %3: homepage URL; "
00376 "--- end of comment ---",
00377 "<h2 style='margin-top: 0px;'>Welcome to Akregator %1</h2>"
00378 "<p>Akregator is an RSS feed aggregator for the K Desktop Environment. "
00379 "Feed aggregators provide a convenient way to browse different kinds of "
00380 "content, including news, blogs, and other content from online sites. "
00381 "Instead of checking all your favorite web sites manually for updates, "
00382 "Akregator collects the content for you.</p>"
00383 "<p>For more information about using Akregator, check the "
00384 "<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>"
00385 "<p>We hope that you will enjoy Akregator.</p>\n"
00386 "<p>Thank you,</p>\n"
00387 "<p style='margin-bottom: 0px'> The Akregator Team</p>\n")
00388 .arg(AKREGATOR_VERSION)
00389 .arg("http://akregator.kde.org/");
00390
00391 QString fontSize = QString::number( pointsToPixel( Settings::mediumFontSize() ));
00392 QString appTitle = i18n("Akregator");
00393 QString catchPhrase = "";
00394 QString quickDescription = i18n("An RSS feed reader for the K Desktop Environment.");
00395 write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
00396 end();
00397 }
00398
00399 QString ArticleViewer::formatArticleNormalMode(Feed* feed, const Article& article)
00400 {
00401 QString text;
00402 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::reverseLayout() ? "rtl" : "ltr");
00403
00404 if (!article.title().isEmpty())
00405 {
00406 text += QString("<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
00407 if (article.link().isValid())
00408 text += "<a href=\""+article.link().url()+"\">";
00409 text += article.title().replace("<", "<").replace(">", ">");
00410 if (article.link().isValid())
00411 text += "</a>";
00412 text += "</div>\n";
00413 }
00414 if (article.pubDate().isValid())
00415 {
00416 text += QString("<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Date")));
00417 text += QString ("%1:").arg(i18n("Date"));
00418 text += "</span><span class=\"headertext\">";
00419 text += KGlobal::locale()->formatDateTime(article.pubDate(), false, false)+"</span>\n";
00420 }
00421 QString author = article.author();
00422 if (!author.isEmpty())
00423 {
00424 text += QString("<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Author")));
00425 text += QString ("%1:").arg(i18n("Author"));
00426 text += "</span><span class=\"headertext\">";
00427 text += author+"</span>\n";
00428 }
00429 text += "</div>\n";
00430
00431 if (feed && !feed->image().isNull())
00432 {
00433 QString file = Utils::fileNameForUrl(feed->xmlUrl());
00434 KURL u(m_imageDir);
00435 u.setFileName(file);
00436 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl()).arg(u.url());
00437 }
00438
00439
00440
00441 if (!article.description().isEmpty())
00442 {
00443 text += QString("<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
00444 text += "<span class=\"content\">"+article.description()+"</span>";
00445 text += "</div>";
00446 }
00447
00448 text += "<div class=\"body\">";
00449
00450 if (article.commentsLink().isValid())
00451 {
00452 text += "<a class=\"contentlink\" href=\"";
00453 text += article.commentsLink().url();
00454 text += "\">" + i18n( "Comments");
00455 if (article.comments())
00456 {
00457 text += " ("+ QString::number(article.comments()) +")";
00458 }
00459 text += "</a>";
00460 }
00461
00462 if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
00463 {
00464 text += "<p><a class=\"contentlink\" href=\"";
00465
00466 if (article.link().isValid())
00467 {
00468 text += article.link().url();
00469 }
00470 else
00471 {
00472 text += article.guid();
00473 }
00474 text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00475 }
00476 text += "</div>";
00477
00478 if (!article.enclosure().isNull())
00479 {
00480
00481
00482
00483
00484
00485
00486 }
00487
00488 return text;
00489
00490 }
00491
00492 QString ArticleViewer::formatArticleCombinedMode(Feed* feed, const Article& article)
00493 {
00494 QString text;
00495 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::reverseLayout() ? "rtl" : "ltr");
00496
00497 KURL link = article.link();
00498
00499 if (!article.title().isEmpty())
00500 {
00501 text += QString("<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
00502 if (link.isValid())
00503 text += "<a href=\""+link.url()+"\">";
00504 text += article.title().replace("<", "<").replace(">", ">");
00505 if (link.isValid())
00506 text += "</a>";
00507 text += "</div>\n";
00508 }
00509 if (article.pubDate().isValid())
00510 {
00511 text += QString("<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Date")));
00512 text += QString ("%1:").arg(i18n("Date"));
00513 text += "</span><span class=\"headertext\">";
00514 text += KGlobal::locale()->formatDateTime(article.pubDate(), false, false)+"</span>\n";
00515 }
00516
00517 QString author = article.author();
00518 if (!author.isEmpty())
00519 {
00520 text += QString("<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Author")));
00521 text += QString ("%1:").arg(i18n("Author"));
00522 text += "</span><span class=\"headertext\">";
00523 text += author+"</span>\n";
00524 }
00525
00526 text += "</div>\n";
00527
00528 if (feed && !feed->image().isNull())
00529 {
00530 QString file = Utils::fileNameForUrl(feed->xmlUrl());
00531 KURL u(m_imageDir);
00532 u.setFileName(file);
00533 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl()).arg(u.url());
00534 }
00535
00536
00537
00538 if (!article.description().isEmpty())
00539 {
00540 text += QString("<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
00541 text += "<span class=\"content\">"+article.description()+"</span>";
00542 text += "</div>";
00543 }
00544
00545 text += "<div class=\"body\">";
00546
00547 if (article.commentsLink().isValid())
00548 {
00549 text += "<a class=\"contentlink\" href=\"";
00550 text += article.commentsLink().url();
00551 text += "\">" + i18n( "Comments");
00552 if (article.comments())
00553 {
00554 text += " ("+ QString::number(article.comments()) +")";
00555 }
00556 text += "</a>";
00557 }
00558
00559 if (link.isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
00560 {
00561 text += "<p><a class=\"contentlink\" href=\"";
00562
00563 if (link.isValid())
00564 {
00565 text += link.url();
00566 }
00567 else
00568 {
00569 text += article.guid();
00570 }
00571 text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00572 }
00573 text += "</div>";
00574
00575 return text;
00576
00577 }
00578
00579 void ArticleViewer::renderContent(const QString& text)
00580 {
00581 closeURL();
00582 m_currentText = text;
00583 beginWriting();
00584
00585 write(text);
00586 endWriting();
00587 }
00588
00589 void ArticleViewer::beginWriting()
00590 {
00591 QString head = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n <html><head><title>.</title></head>");
00592 view()->setContentsPos(0,0);
00593 begin(m_link);
00594 setUserStyleSheet(m_viewMode == CombinedView ? m_combinedModeCSS : m_normalModeCSS);
00595 write(head);
00596 }
00597
00598 void ArticleViewer::endWriting()
00599 {
00600 write(m_htmlFooter);
00601
00602 end();
00603 }
00604
00605 void ArticleViewer::slotShowSummary(TreeNode* node)
00606 {
00607 m_viewMode = SummaryView;
00608
00609 if (!node)
00610 {
00611 slotClear();
00612 return;
00613 }
00614
00615 if (node != m_node)
00616 {
00617 disconnectFromNode(m_node);
00618 connectToNode(node);
00619 m_node = node;
00620 }
00621 m_showSummaryVisitor->visit(node);
00622 }
00623
00624
00625 void ArticleViewer::slotShowArticle(const Article& article)
00626 {
00627 m_viewMode = NormalView;
00628 disconnectFromNode(m_node);
00629 m_article = article;
00630 m_node = 0;
00631 m_link = article.link();
00632 if (article.feed()->loadLinkedWebsite())
00633 openURL(article.link());
00634 else
00635 renderContent( formatArticleNormalMode(article.feed(), article) );
00636 }
00637
00638 void ArticleViewer::slotSetFilter(const Akregator::Filters::ArticleMatcher& textFilter, const Akregator::Filters::ArticleMatcher& statusFilter)
00639 {
00640 if (m_statusFilter == statusFilter && m_textFilter == textFilter)
00641 return;
00642
00643 m_textFilter = textFilter;
00644 m_statusFilter = statusFilter;
00645
00646 slotUpdateCombinedView();
00647 }
00648
00649 void ArticleViewer::slotUpdateCombinedView()
00650 {
00651 if (m_viewMode != CombinedView)
00652 return;
00653
00654 if (!m_node)
00655 return slotClear();
00656
00657 QValueList<Article> articles = m_node->articles();
00658 qHeapSort(articles);
00659 QValueList<Article>::ConstIterator end = articles.end();
00660 QValueList<Article>::ConstIterator it = articles.begin();
00661
00662 QString text;
00663
00664 int num = 0;
00665 QTime spent;
00666 spent.start();
00667
00668 for ( ; it != end; ++it)
00669 {
00670 if ( !(*it).isDeleted() && m_textFilter.matches(*it) && m_statusFilter.matches(*it) )
00671 {
00672 text += "<p><div class=\"article\">"+formatArticleCombinedMode(0, *it)+"</div><p>";
00673 ++num;
00674 }
00675 }
00676
00677 renderContent(text);
00678
00679
00680
00681 }
00682
00683 void ArticleViewer::slotArticlesUpdated(TreeNode* , const QValueList<Article>& )
00684 {
00685 if (m_viewMode == CombinedView)
00686 slotUpdateCombinedView();
00687 }
00688
00689 void ArticleViewer::slotArticlesAdded(TreeNode* , const QValueList<Article>& )
00690 {
00691 }
00692
00693 void ArticleViewer::slotArticlesRemoved(TreeNode* , const QValueList<Article>& )
00694 {
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 void ArticleViewer::slotClear()
00706 {
00707 disconnectFromNode(m_node);
00708 m_node = 0;
00709 m_article = Article();
00710
00711 renderContent(QString());
00712 }
00713
00714 void ArticleViewer::slotShowNode(TreeNode* node)
00715 {
00716 m_viewMode = CombinedView;
00717
00718 if (node != m_node)
00719 disconnectFromNode(m_node);
00720
00721 connectToNode(node);
00722
00723 m_article = Article();
00724 m_node = node;
00725
00726 if (node && !node->articles().isEmpty())
00727 m_link = node->articles().first().link();
00728 else
00729 m_link = KURL();
00730
00731 slotUpdateCombinedView();
00732 }
00733
00734 void ArticleViewer::keyPressEvent(QKeyEvent* e)
00735 {
00736 e->ignore();
00737 }
00738
00739 void ArticleViewer::urlSelected(const QString &url, int button, int state, const QString& _target, KParts::URLArgs args)
00740 {
00741 if(url == "config:/disable_introduction") {
00742 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) {
00743 KConfig *conf = Settings::self()->config();
00744 conf->setGroup("General");
00745 conf->writeEntry("Disable Introduction", "true");
00746 }
00747 }
00748 else
00749 Viewer::urlSelected(url, button, state, _target, args);
00750 }
00751
00752 void ArticleViewer::slotPaletteOrFontChanged()
00753 {
00754 generateNormalModeCSS();
00755 generateCombinedModeCSS();
00756 reload();
00757 }
00758
00759 void ArticleViewer::connectToNode(TreeNode* node)
00760 {
00761 if (node)
00762 {
00763 if (m_viewMode == CombinedView)
00764 {
00765
00766 connect( node, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesAdded(TreeNode*, const QValueList<Article>&)));
00767 connect( node, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesRemoved(TreeNode*, const QValueList<Article>&)));
00768 connect( node, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesUpdated(TreeNode*, const QValueList<Article>&)));
00769 }
00770 if (m_viewMode == SummaryView)
00771 connect( node, SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotShowSummary(TreeNode*) ) );
00772
00773 connect( node, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotClear() ) );
00774 }
00775 }
00776
00777 void ArticleViewer::disconnectFromNode(TreeNode* node)
00778 {
00779 if (node)
00780 {
00781
00782 disconnect( node, SIGNAL(signalDestroyed(TreeNode*)), this, SLOT(slotClear() ) );
00783 disconnect( node, SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotShowSummary(TreeNode*) ) );
00784 disconnect( node, SIGNAL(signalArticlesAdded(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesAdded(TreeNode*, const QValueList<Article>&)));
00785 disconnect( node, SIGNAL(signalArticlesRemoved(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesRemoved(TreeNode*, const QValueList<Article>&)));
00786 disconnect( node, SIGNAL(signalArticlesUpdated(TreeNode*, const QValueList<Article>&)), this, SLOT(slotArticlesUpdated(TreeNode*, const QValueList<Article>&)));
00787
00788 }
00789 }
00790
00791 }
00792 #include "articleviewer.moc"
00793