akregator/src

articleviewer.cpp
00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>
00005                   2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of TQt, and distribute the resulting executable,
00022     without including the source code for TQt in the source distribution.
00023 */
00024 
00025 #include <tqdatetime.h>
00026 #include <tqevent.h>
00027 #include <tqscrollview.h>
00028 #include <tqvaluelist.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 // from kmail::headerstyle.cpp
00059 static inline TQString directionOf(const TQString &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 = TQString();
00073         
00074         TQString text;
00075         text = TQString("<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ? "rtl" : "ltr");
00076         
00077         text += TQString("<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"; // headertitle
00084         text += "</div>\n"; // /headerbox
00085         
00086         if (!node->image().isNull()) // image
00087         {
00088             text += TQString("<div class=\"body\">");
00089             TQString url=node->xmlUrl();
00090             TQString file = url.replace("/", "_").replace(":", "_");
00091             KURL u(m_view->m_imageDir);
00092             u.setFileName(file);
00093             text += TQString("<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 += TQString("<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"; // /description
00103         }
00104         
00105         if ( !node->htmlUrl().isEmpty() )
00106         {
00107             text += TQString("<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"; // / link
00110         }
00111         
00112         //text += i18n("<b>Unread articles:</b> %1").arg(node->unread());
00113         text += "</div>"; // /body
00114         
00115         m_view->renderContent(text);
00116         return true;
00117     }
00118     
00119     virtual bool visitFolder(Folder* node)
00120     {
00121         m_view->m_link = TQString();
00122         
00123         TQString text;
00124         text = TQString("<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ? "rtl" : "ltr");
00125         text += TQString("<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 += TQString("</div>\n");
00131         text += "</div>\n"; // /headerbox
00132     
00133         m_view->renderContent(text);
00134         return true;
00135     }
00136 
00137     virtual bool visitTagNode(TagNode* node)
00138     {
00139         m_view->m_link = TQString();
00140         
00141         TQString text;
00142         text = TQString("<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ? "rtl" : "ltr");
00143         text += TQString("<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 += TQString("</div>\n");
00149         text += "</div>\n"; // /headerbox
00150     
00151         m_view->renderContent(text);
00152         return true;
00153     }
00154 
00155     private:
00156 
00157     ArticleViewer* m_view;
00158 };
00159 
00160 ArticleViewer::ArticleViewer(TQWidget *parent, const char *name)
00161     : Viewer(parent, name), m_htmlFooter(), m_currentText(), m_node(0), m_viewMode(NormalView)
00162 {
00163     setJScriptEnabled(false);
00164     setJavaEnabled(false);
00165     setPluginsEnabled(false);
00166     
00167     m_showSummaryVisitor = new ShowSummaryVisitor(this);
00168     setXMLFile(locate("data", "akregator/articleviewer.rc"), true);
00169 
00170     generateNormalModeCSS();
00171     generateCombinedModeCSS();
00172     new KAction( i18n("&Scroll Up"), TQString(), "Up", this, TQT_SLOT(slotScrollUp()), actionCollection(), "articleviewer_scroll_up" );
00173     new KAction( i18n("&Scroll Down"), TQString(), "Down", this, TQT_SLOT(slotScrollDown()), actionCollection(), "articleviewer_scroll_down" );
00174     
00175     connect(this, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotSelectionChanged()));
00176 
00177     connect(kapp, TQT_SIGNAL(kdisplayPaletteChanged()), this, TQT_SLOT(slotPaletteOrFontChanged()) );
00178     connect(kapp, TQT_SIGNAL(kdisplayFontChanged()), this, TQT_SLOT(slotPaletteOrFontChanged()) );
00179     
00180     m_imageDir.setPath(KGlobal::dirs()->saveLocation("cache", "akregator/Media/"));
00181     m_htmlFooter = "</body></html>";
00182 }
00183 
00184 ArticleViewer::~ArticleViewer()
00185 {
00186     delete m_showSummaryVisitor;
00187 }
00188 
00189 void ArticleViewer::generateNormalModeCSS()
00190 {
00191     const TQColorGroup & cg = TQApplication::palette().active();
00192     
00193     // from kmail::headerstyle.cpp
00194     m_normalModeCSS = TQString(
00195             "@media screen, print {"
00196             "body {\n"
00197             "  font-family: \"%1\" ! important;\n"
00198             "  font-size: %2 ! important;\n"
00199             "  color: %3 ! important;\n"
00200             "  background: %4 ! important;\n"
00201             "}\n\n").arg(Settings::standardFont())
00202             .arg(TQString::number(pointsToPixel(Settings::mediumFontSize()))+"px")
00203             .arg(cg.text().name())
00204             .arg(cg.base().name());
00205     m_normalModeCSS += TQString(
00206     "a {\n"
00207     + TQString("  color: %1 ! important;\n")
00208     + TQString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00209     +       "}\n\n"
00210     +".headerbox {\n"
00211     +"  background: %2 ! important;\n"
00212     +"  color: %3 ! important;\n"
00213     +"  border:1px solid #000;\n"
00214     +"  margin-bottom: 10pt;\n"
00215 //    +"  width: 99%;\n"
00216     +        "}\n\n")
00217             .arg(cg.link().name())
00218             .arg(cg.background().name())
00219             .arg(cg.text().name());
00220 
00221     m_normalModeCSS += TQString(".headertitle a:link { color: %1  ! important; }\n"
00222     ".headertitle a:visited { color: %2 ! important; }\n"
00223     ".headertitle a:hover{ color: %3 ! important; }\n"
00224             ".headertitle a:active { color: %4 ! important; }\n")
00225             .arg(cg.highlightedText().name())
00226             .arg(cg.highlightedText().name())
00227             .arg(cg.highlightedText().name())
00228             .arg(cg.highlightedText().name());
00229     
00230     m_normalModeCSS += TQString(
00231     ".headertitle {\n"
00232     "  background: %1 ! important;\n"
00233     "  padding:2px;\n"
00234     "  color: %2 ! important;\n"
00235     "  font-weight: bold;\n"
00236     "}\n\n"
00237     ".header {\n"
00238     "  font-weight: bold;\n"
00239     "  padding:2px;\n"
00240     "  margin-right: 5px;\n"
00241     "}\n\n"
00242     ".headertext {\n"
00243     "}\n\n"
00244     ".headimage {\n"
00245     "  float: right;\n"
00246     "  margin-left: 5px;\n"
00247             "}\n\n").arg(cg.highlight().name())
00248             .arg(cg.highlightedText().name());
00249     
00250     m_normalModeCSS += TQString(
00251     "body { clear: none; }\n\n"
00252     ".content {\n"
00253     "  display: block;\n"
00254     "  margin-bottom: 6px;\n"
00255             "}\n\n"
00256     // these rules make sure that there is no leading space between the header and the first of the text
00257     ".content > P:first-child {\n margin-top: 1px; }\n"
00258     ".content > DIV:first-child {\n margin-top: 1px; }\n"
00259     ".content > BR:first-child {\n display: none;  }\n"
00260     "iframe {display: none !important; }\n"
00261     "frame {display: none !important; }\n"
00262     "frameset {display: none !important; }\n"
00263     "object {display: none !important; }\n"
00264     "applet {display: none !important; }\n"
00265     "}\n\n"); // @media screen, print    
00266 }
00267 
00268 void ArticleViewer::generateCombinedModeCSS()
00269 {
00270     const TQColorGroup & cg = TQApplication::palette().active();
00271     
00272     // from kmail::headerstyle.cpp
00273     m_combinedModeCSS = TQString (
00274 //            "<style type=\"text/css\">\n"
00275             "@media screen, print {"
00276             "body {\n"
00277             "  font-family: \"%1\" ! important;\n"
00278             "  font-size: %2 ! important;\n"
00279             "  color: %3 ! important;\n"
00280             "  background: %4 ! important;\n"
00281             "}\n\n").arg(Settings::standardFont())
00282             .arg(TQString::number(pointsToPixel(Settings::mediumFontSize()))+"px")
00283             .arg(cg.text().name())
00284             .arg(cg.base().name());
00285     m_combinedModeCSS += (
00286     "a {\n"
00287     + TQString("  color: %1 ! important;\n")
00288     + TQString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00289     +       "}\n\n"
00290     +".headerbox {\n"
00291     +"  background: %2 ! important;\n"
00292     +"  color: %3 ! important;\n"
00293     +"  border:1px solid #000;\n"
00294     +"  margin-bottom: 10pt;\n"
00295 //    +"  width: 99%;\n"
00296     +        "}\n\n")
00297             .arg(cg.link().name())
00298             .arg(cg.background().name())
00299             .arg(cg.text().name());
00300 
00301     m_combinedModeCSS += TQString(".headertitle a:link { color: %1  ! important; }\n"
00302     ".headertitle a:visited { color: %2 ! important; }\n"
00303     ".headertitle a:hover{ color: %3 ! important; }\n"
00304             ".headertitle a:active { color: %4 ! important; }\n")
00305             .arg(cg.highlightedText().name())
00306             .arg(cg.highlightedText().name())
00307             .arg(cg.highlightedText().name())
00308             .arg(cg.highlightedText().name());
00309     m_combinedModeCSS += TQString(
00310     ".headertitle {\n"
00311     "  background: %1 ! important;\n"
00312     "  padding:2px;\n"
00313     "  color: %2 ! important;\n"
00314     "  font-weight: bold;\n"
00315     "}\n\n"
00316     ".header {\n"
00317     "  font-weight: bold;\n"
00318     "  padding:2px;\n"
00319     "  margin-right: 5px;\n"
00320     "}\n\n"
00321     ".headertext {\n"
00322     "}\n\n"
00323     ".headimage {\n"
00324     "  float: right;\n"
00325     "  margin-left: 5px;\n"
00326             "}\n\n").arg(cg.highlight().name())
00327             .arg(cg.highlightedText().name());
00328     
00329     m_combinedModeCSS += TQString(
00330     "body { clear: none; }\n\n"
00331     ".content {\n"
00332     "  display: block;\n"
00333     "  margin-bottom: 6px;\n"
00334             "}\n\n"
00335     // these rules make sure that there is no leading space between the header and the first of the text
00336     ".content > P:first-child {\n margin-top: 1px; }\n"
00337     ".content > DIV:first-child {\n margin-top: 1px; }\n"
00338     ".content > BR:first-child {\n display: none;  }\n"
00339     "iframe {display: none !important; }\n"
00340     "frame {display: none !important; }\n"
00341     "frameset {display: none !important; }\n"
00342     "object {display: none !important; }\n"
00343     "applet {display: none !important; }\n"
00344     "}\n\n"); // @media screen, print
00345 }
00346 
00347 void ArticleViewer::reload()
00348 {
00349     beginWriting();
00350     write(m_currentText);
00351     endWriting();
00352 }
00353 
00354 bool ArticleViewer::openURL(const KURL& url)
00355 {
00356     if (!m_article.isNull() && m_article.feed()->loadLinkedWebsite())
00357     {
00358         return Viewer::openURL(url);
00359     }
00360     else
00361     {
00362         reload();
00363         return true;
00364     }
00365 }
00366 
00367 void ArticleViewer::displayAboutPage()
00368 {
00369     TQString location = locate("data", "akregator/about/main.html");
00370     TQString content = KPIM::kFileToString(location);
00371     content = content.arg( locate( "data", "libkdepim/about/kde_infopage.css" ) );
00372     if ( kapp->reverseLayout() )
00373         content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libkdepim/about/kde_infopage_rtl.css" ) );
00374     else
00375         content = content.arg( "" );
00376 
00377     begin(KURL( location ));
00378     TQString info =
00379             i18n("%1: Akregator version; %2: help:// URL; %3: homepage URL; "
00380             "--- end of comment ---",
00381     "<h2 style='margin-top: 0px;'>Welcome to Akregator %1</h2>"
00382             "<p>Akregator is an RSS feed aggregator for the K Desktop Environment. "
00383             "Feed aggregators provide a convenient way to browse different kinds of "
00384             "content, including news, blogs, and other content from online sites. "
00385             "Instead of checking all your favorite web sites manually for updates, "
00386             "Akregator collects the content for you.</p>"
00387             "<p>For more information about using Akregator, check the "
00388             "<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>"
00389             "<p>We hope that you will enjoy Akregator.</p>\n"
00390             "<p>Thank you,</p>\n"
00391             "<p style='margin-bottom: 0px'>&nbsp; &nbsp; The Akregator Team</p>\n")
00392             .arg(AKREGATOR_VERSION) // Akregator version
00393             .arg("http://akregator.kde.org/"); // Akregator homepage URL
00394 
00395     TQString fontSize = TQString::number( pointsToPixel( Settings::mediumFontSize() ));
00396     TQString appTitle = i18n("Akregator");
00397     TQString catchPhrase = ""; //not enough space for a catch phrase at default window size i18n("Part of the Kontact Suite");
00398     TQString quickDescription = i18n("An RSS feed reader for the K Desktop Environment.");
00399     write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
00400     end();
00401 }
00402 
00403 TQString ArticleViewer::formatArticleNormalMode(Feed* feed, const Article& article)
00404 {
00405     TQString text;
00406     text = TQString("<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ? "rtl" : "ltr");
00407 
00408     if (!article.title().isEmpty())
00409     {
00410         text += TQString("<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
00411         if (article.link().isValid())
00412             text += "<a href=\""+article.link().url()+"\">";
00413         text += article.title().replace("<", "&lt;").replace(">", "&gt;"); // TODO: better leave things escaped in the parser
00414         if (article.link().isValid())
00415             text += "</a>";
00416         text += "</div>\n";
00417     }
00418     if (article.pubDate().isValid())
00419     {
00420         text += TQString("<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Date")));
00421         text += TQString ("%1:").arg(i18n("Date"));
00422         text += "</span><span class=\"headertext\">";
00423         text += KGlobal::locale()->formatDateTime(article.pubDate(), false, false)+"</span>\n"; // TODO: might need RTL?
00424     }
00425     TQString author = article.author();
00426     if (!author.isEmpty())
00427     {
00428         text += TQString("<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Author")));
00429         text += TQString ("%1:").arg(i18n("Author"));
00430         text += "</span><span class=\"headertext\">";
00431         text += author+"</span>\n"; // TODO: might need RTL?
00432     }
00433     text += "</div>\n"; // end headerbox
00434 
00435     if (feed && !feed->image().isNull())
00436     {
00437         TQString file = Utils::fileNameForUrl(feed->xmlUrl());
00438         KURL u(m_imageDir);
00439         u.setFileName(file);
00440         text += TQString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl()).arg(u.url());
00441     }
00442 
00443     
00444 
00445     if (!article.description().isEmpty())
00446     {
00447         text += TQString("<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
00448         text += "<span class=\"content\">"+article.description()+"</span>";
00449         text += "</div>";
00450     }
00451     
00452     text += "<div class=\"body\">";
00453     
00454     if (article.commentsLink().isValid())
00455     {
00456         text += "<a class=\"contentlink\" href=\"";
00457         text += article.commentsLink().url();
00458         text += "\">" + i18n( "Comments");
00459         if (article.comments())
00460         {
00461             text += " ("+ TQString::number(article.comments()) +")";
00462         }
00463         text += "</a>";
00464     }
00465 
00466     if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
00467     {
00468         text += "<p><a class=\"contentlink\" href=\"";
00469         // in case link isn't valid, fall back to the guid permaLink.
00470         if (article.link().isValid())
00471         {
00472             text += article.link().url();
00473         }
00474         else
00475          {
00476             text += article.guid();
00477         }
00478         text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00479     }
00480     text += "</div>";
00481     
00482     if (!article.enclosure().isNull())
00483     {
00484         //TQString url = article.enclosure().url();
00485         //TQString type = article.enclosure().type();
00486         //int length = article.enclosure().length();
00487         //TQString lengthStr = KIO::convertSize(length);
00488 
00489         //text += TQString("<hr><div><a href=\"%1\">%2</a> (%3, %4)</div>").arg(url).arg(url).arg(lengthStr).arg(type);
00490     }
00491     //kdDebug() << text << endl;
00492     return text;
00493 
00494 }
00495 
00496 TQString ArticleViewer::formatArticleCombinedMode(Feed* feed, const Article& article)
00497 {
00498     TQString text;
00499     text = TQString("<div class=\"headerbox\" dir=\"%1\">\n").arg(TQApplication::reverseLayout() ? "rtl" : "ltr");
00500 
00501     KURL link = article.link();
00502     
00503     if (!article.title().isEmpty())
00504     {
00505         text += TQString("<div class=\"headertitle\" dir=\"%1\">\n").arg(directionOf(Utils::stripTags(article.title())));
00506         if (link.isValid())
00507             text += "<a href=\""+link.url()+"\">";
00508         text += article.title().replace("<", "&lt;").replace(">", "&gt;"); // TODO: better leave things escaped in the parser
00509         if (link.isValid())
00510             text += "</a>";
00511         text += "</div>\n";
00512     }
00513     if (article.pubDate().isValid())
00514     {
00515         text += TQString("<span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Date")));
00516         text += TQString ("%1:").arg(i18n("Date"));
00517         text += "</span><span class=\"headertext\">";
00518         text += KGlobal::locale()->formatDateTime(article.pubDate(), false, false)+"</span>\n"; // TODO: might need RTL?
00519     }
00520     
00521     TQString author = article.author();
00522     if (!author.isEmpty())
00523     {
00524         text += TQString("<br/><span class=\"header\" dir=\"%1\">").arg(directionOf(i18n("Author")));
00525         text += TQString ("%1:").arg(i18n("Author"));
00526         text += "</span><span class=\"headertext\">";
00527         text += author+"</span>\n"; // TODO: might need RTL?
00528     }
00529     
00530     text += "</div>\n"; // end headerbox
00531 
00532     if (feed && !feed->image().isNull())
00533     {
00534         TQString file = Utils::fileNameForUrl(feed->xmlUrl());
00535         KURL u(m_imageDir);
00536         u.setFileName(file);
00537         text += TQString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl()).arg(u.url());
00538     }
00539 
00540     
00541 
00542     if (!article.description().isEmpty())
00543     {
00544         text += TQString("<div dir=\"%1\">").arg(directionOf(Utils::stripTags(article.description())) );
00545         text += "<span class=\"content\">"+article.description()+"</span>";
00546         text += "</div>";
00547     }
00548     
00549     text += "<div class=\"body\">";
00550     
00551     if (article.commentsLink().isValid())
00552     {
00553         text += "<a class=\"contentlink\" href=\"";
00554         text += article.commentsLink().url();
00555         text += "\">" + i18n( "Comments");
00556         if (article.comments())
00557         {
00558             text += " ("+ TQString::number(article.comments()) +")";
00559         }
00560         text += "</a>";
00561     }
00562 
00563     if (link.isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
00564     {
00565         text += "<p><a class=\"contentlink\" href=\"";
00566         // in case link isn't valid, fall back to the guid permaLink.
00567         if (link.isValid())
00568         {
00569             text += link.url();
00570         }
00571         else
00572          {
00573             text += article.guid();
00574         }
00575         text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00576     }
00577     text += "</div>";
00578     //kdDebug() << text << endl;
00579     return text;
00580 
00581 }
00582 
00583 void ArticleViewer::renderContent(const TQString& text)
00584 {
00585     closeURL();
00586     m_currentText = text;
00587     beginWriting();
00588     //kdDebug() << text << endl;
00589     write(text);
00590     endWriting();
00591 }
00592 
00593 void ArticleViewer::beginWriting()
00594 {
00595     TQString head = TQString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n <html><head><title>.</title></head>");
00596     view()->setContentsPos(0,0);
00597     begin(m_link);
00598     setUserStyleSheet(m_viewMode == CombinedView ? m_combinedModeCSS : m_normalModeCSS);
00599     write(head);
00600 }
00601 
00602 void ArticleViewer::endWriting()
00603 {
00604     write(m_htmlFooter);
00605     //kdDebug() << m_htmlFooter << endl;
00606     end();
00607 }
00608 
00609 void ArticleViewer::slotShowSummary(TreeNode* node)
00610 {
00611     m_viewMode = SummaryView;
00612 
00613     if (!node)
00614     {
00615         slotClear();
00616         return;
00617     }
00618 
00619     if (node != m_node)
00620     {
00621         disconnectFromNode(m_node);
00622         connectToNode(node);
00623         m_node = node;
00624     }
00625     m_showSummaryVisitor->visit(node);
00626 }
00627 
00628 
00629 void ArticleViewer::slotShowArticle(const Article& article)
00630 {
00631     m_viewMode = NormalView;
00632     disconnectFromNode(m_node);
00633     m_article = article;
00634     m_node = 0;
00635     m_link = article.link();
00636     if (article.feed()->loadLinkedWebsite())
00637         openURL(article.link());
00638     else
00639         renderContent( formatArticleNormalMode(article.feed(), article) );
00640 }
00641 
00642 void ArticleViewer::slotSetFilter(const Akregator::Filters::ArticleMatcher& textFilter, const Akregator::Filters::ArticleMatcher& statusFilter)
00643 {
00644     if (m_statusFilter == statusFilter && m_textFilter == textFilter)
00645         return;
00646 
00647     m_textFilter = textFilter;
00648     m_statusFilter = statusFilter;
00649 
00650     slotUpdateCombinedView();
00651 }
00652 
00653 void ArticleViewer::slotUpdateCombinedView()
00654 {
00655     if (m_viewMode != CombinedView)
00656         return;
00657 
00658     if (!m_node)
00659         return slotClear();
00660 
00661     TQValueList<Article> articles = m_node->articles();
00662     qHeapSort(articles);
00663     TQValueList<Article>::ConstIterator end = articles.end();
00664     TQValueList<Article>::ConstIterator it = articles.begin();
00665 
00666     TQString text;
00667 
00668     int num = 0;
00669     TQTime spent;
00670     spent.start();
00671     
00672     for ( ; it != end; ++it)
00673     {
00674         if ( !(*it).isDeleted() && m_textFilter.matches(*it) && m_statusFilter.matches(*it) )
00675         {
00676             text += "<p><div class=\"article\">"+formatArticleCombinedMode(0, *it)+"</div><p>";
00677             ++num;
00678         }
00679     }
00680     //kdDebug() << "Combined view rendering: (" << num << " articles):\n" << "generating HTML: " << spent.elapsed() << "ms " << endl;
00681     renderContent(text);
00682     //kdDebug() << "HTML rendering: " << spent.elapsed() << "ms" << endl;
00683 
00684 
00685 }
00686 
00687 void ArticleViewer::slotArticlesUpdated(TreeNode* /*node*/, const TQValueList<Article>& /*list*/)
00688 {
00689     if (m_viewMode == CombinedView)
00690         slotUpdateCombinedView();
00691 }
00692 
00693 void ArticleViewer::slotArticlesAdded(TreeNode* /*node*/, const TQValueList<Article>& /*list*/)
00694 {
00695 }
00696 
00697 void ArticleViewer::slotArticlesRemoved(TreeNode* /*node*/, const TQValueList<Article>& /*list*/)
00698 {
00699 }
00700 
00701 /* testingtesting :)
00702 void ArticleViewer::slotPopupMenu(KXMLGUIClient*, const TQPoint& p, const KURL& kurl, const KParts::URLArgs&, KParts::BrowserExtension::PopupFlags, mode_t)
00703 {
00704     kdDebug() << m_link << endl;
00705     kdDebug() << kurl.url() << endl;
00706 }*/
00707 
00708 
00709 void ArticleViewer::slotClear()
00710 {
00711     disconnectFromNode(m_node);
00712     m_node = 0;
00713     m_article = Article();
00714 
00715     renderContent(TQString());
00716 }
00717 
00718 void ArticleViewer::slotShowNode(TreeNode* node)
00719 {
00720     m_viewMode = CombinedView;
00721 
00722     if (node != m_node)
00723         disconnectFromNode(m_node);
00724 
00725     connectToNode(node);
00726     
00727     m_article = Article();
00728     m_node = node;
00729 
00730     if (node && !node->articles().isEmpty())
00731         m_link = node->articles().first().link();
00732     else
00733         m_link = KURL();
00734 
00735     slotUpdateCombinedView();
00736 }
00737 
00738 void ArticleViewer::keyPressEvent(TQKeyEvent* e)
00739 {
00740     e->ignore();
00741 }
00742 
00743 void ArticleViewer::urlSelected(const TQString &url, int button, int state, const TQString& _target, KParts::URLArgs args)
00744 {
00745     if(url == "config:/disable_introduction") {
00746         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) {
00747             KConfig *conf = Settings::self()->config();
00748             conf->setGroup("General");
00749             conf->writeEntry("Disable Introduction", "true");
00750         }
00751     }
00752     else
00753         Viewer::urlSelected(url, button, state, _target, args);
00754 }
00755 
00756 void ArticleViewer::slotPaletteOrFontChanged()
00757 {
00758     generateNormalModeCSS();
00759     generateCombinedModeCSS();
00760     reload();
00761 }
00762 
00763 void ArticleViewer::connectToNode(TreeNode* node)
00764 {
00765     if (node)
00766     {
00767         if (m_viewMode == CombinedView)
00768         {
00769 //            connect( node, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotUpdateCombinedView() ) );
00770             connect( node, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesAdded(TreeNode*, const TQValueList<Article>&)));
00771             connect( node, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
00772             connect( node, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
00773         }
00774         if (m_viewMode == SummaryView)
00775             connect( node, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotShowSummary(TreeNode*) ) );
00776 
00777         connect( node, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotClear() ) );
00778     }   
00779 }
00780 
00781 void ArticleViewer::disconnectFromNode(TreeNode* node)
00782 {
00783     if (node)
00784     {
00785 //        disconnect( node, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotUpdateCombinedView() ) );
00786         disconnect( node, TQT_SIGNAL(signalDestroyed(TreeNode*)), this, TQT_SLOT(slotClear() ) );
00787         disconnect( node, TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotShowSummary(TreeNode*) ) );
00788         disconnect( node, TQT_SIGNAL(signalArticlesAdded(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesAdded(TreeNode*, const TQValueList<Article>&)));
00789         disconnect( node, TQT_SIGNAL(signalArticlesRemoved(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesRemoved(TreeNode*, const TQValueList<Article>&)));
00790         disconnect( node, TQT_SIGNAL(signalArticlesUpdated(TreeNode*, const TQValueList<Article>&)), this, TQT_SLOT(slotArticlesUpdated(TreeNode*, const TQValueList<Article>&)));
00791 
00792     }
00793 }
00794 
00795 }
00796 #include "articleviewer.moc"
00797