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