akregator
articleformatter.cpp
Go to the documentation of this file.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 "akregatorconfig.h"
00026 #include "article.h"
00027 #include "articleformatter.h"
00028 #include "feed.h"
00029 #include "folder.h"
00030 #include "treenode.h"
00031 #include "treenodevisitor.h"
00032 #include "utils.h"
00033
00034 #include <kglobal.h>
00035 #include <klocale.h>
00036
00037 #include <QApplication>
00038 #include <QPaintDevice>
00039 #include <QPalette>
00040 #include <QString>
00041
00042 namespace Akregator {
00043
00044 class ArticleFormatter::Private
00045 {
00046 public:
00047 explicit Private( QPaintDevice* device_ );
00048 QPaintDevice* device;
00049 class SummaryVisitor;
00050 };
00051
00052 ArticleFormatter::Private::Private( QPaintDevice* device_ ) : device( device_ )
00053 {
00054 }
00055
00056 ArticleFormatter::ArticleFormatter( QPaintDevice* device ) : d( new Private( device ) )
00057 {
00058 }
00059
00060 ArticleFormatter::~ArticleFormatter()
00061 {
00062 delete d;
00063 }
00064
00065 void ArticleFormatter::setPaintDevice(QPaintDevice* device)
00066 {
00067 d->device = device;
00068 }
00069
00070 int ArticleFormatter::pointsToPixel(int pointSize) const
00071 {
00072 return ( pointSize * d->device->logicalDpiY() + 36 ) / 72 ;
00073 }
00074
00075 class DefaultNormalViewFormatter::SummaryVisitor : public TreeNodeVisitor
00076 {
00077 public:
00078 SummaryVisitor(DefaultNormalViewFormatter* p) : parent(p) {}
00079 virtual bool visitFeed(Feed* node)
00080 {
00081 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::isRightToLeft() ? "rtl" : "ltr");
00082
00083 text += QString("<div class=\"headertitle\" dir=\"%1\">").arg(Utils::directionOf(Utils::stripTags(node->title())));
00084 text += node->title();
00085 if(node->unread() == 0)
00086 text += i18n(" (no unread articles)");
00087 else
00088 text += i18np(" (1 unread article)", " (%1 unread articles)", node->unread());
00089 text += "</div>\n";
00090 text += "</div>\n";
00091
00092 if (!node->image().isNull())
00093 {
00094 text += QString("<div class=\"body\">");
00095 QString file = Utils::fileNameForUrl(node->xmlUrl());
00096 KUrl u(parent->m_imageDir);
00097 u.setFileName(file);
00098 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(node->htmlUrl(), u.url());
00099 }
00100 else text += "<div class=\"body\">";
00101
00102
00103 if( !node->description().isEmpty() )
00104 {
00105 text += QString("<div dir=\"%1\">").arg(Utils::stripTags(Utils::directionOf(node->description())));
00106 text += i18n("<b>Description:</b> %1<br /><br />", node->description());
00107 text += "</div>\n";
00108 }
00109
00110 if ( !node->htmlUrl().isEmpty() )
00111 {
00112 text += QString("<div dir=\"%1\">").arg(Utils::directionOf(node->htmlUrl()));
00113 text += i18n("<b>Homepage:</b> <a href=\"%1\">%2</a>", node->htmlUrl(), node->htmlUrl());
00114 text += "</div>\n";
00115 }
00116
00117
00118 text += "</div>";
00119
00120 return true;
00121 }
00122
00123 virtual bool visitFolder(Folder* node)
00124 {
00125 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::isRightToLeft() ? "rtl" : "ltr");
00126 text += QString("<div class=\"headertitle\" dir=\"%1\">%2").arg(Utils::directionOf(Utils::stripTags(node->title())), node->title());
00127 if(node->unread() == 0)
00128 text += i18n(" (no unread articles)");
00129 else
00130 text += i18np(" (1 unread article)", " (%1 unread articles)", node->unread());
00131 text += QString("</div>\n");
00132 text += "</div>\n";
00133
00134 return true;
00135 }
00136
00137 QString formatSummary(TreeNode* node)
00138 {
00139 text = QString();
00140 visit(node);
00141 return text;
00142 }
00143
00144 QString text;
00145 DefaultNormalViewFormatter* parent;
00146 };
00147
00148 QString DefaultNormalViewFormatter::formatArticle(const Article& article, IconOption icon) const
00149 {
00150 QString text;
00151 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::isRightToLeft() ? "rtl" : "ltr");
00152
00153 if (!article.title().isEmpty())
00154 {
00155 text += QString("<div class=\"headertitle\" dir=\"%1\">\n").arg(Utils::directionOf(Utils::stripTags(article.title())));
00156 if (article.link().isValid())
00157 text += "<a href=\""+article.link().url()+"\">";
00158 text += article.title().replace("<", "<").replace(">", ">");
00159 if (article.link().isValid())
00160 text += "</a>";
00161 text += "</div>\n";
00162 }
00163 if (article.pubDate().isValid())
00164 {
00165 text += QString("<span class=\"header\" dir=\"%1\">").arg(Utils::directionOf(i18n("Date")));
00166 text += QString ("%1:").arg(i18n("Date"));
00167 text += "</span><span class=\"headertext\">";
00168 text += KGlobal::locale()->formatDateTime(article.pubDate(), KLocale::LongDate, false)+"</span>\n";
00169 }
00170 const QString author = article.authorAsHtml();
00171 if (!author.isEmpty())
00172 {
00173 text += QString("<br/><span class=\"header\" dir=\"%1\">").arg(Utils::directionOf(i18n("Author")));
00174 text += QString ("%1:").arg(i18n("Author"));
00175 text += "</span><span class=\"headertext\">";
00176 text += author+"</span>\n";
00177 }
00178 text += "</div>\n";
00179
00180
00181 if (icon == ShowIcon && article.feed() && !article.feed()->image().isNull())
00182 {
00183 const Feed* feed = article.feed();
00184 QString file = Utils::fileNameForUrl(feed->xmlUrl());
00185 KUrl u(m_imageDir);
00186 u.setFileName(file);
00187 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl(), u.url());
00188 }
00189
00190 const QString content = article.content( Article::DescriptionAsFallback );
00191 if (!content.isEmpty())
00192 {
00193 text += QString("<div dir=\"%1\">").arg(Utils::directionOf(Utils::stripTags(content)) );
00194 text += "<span class=\"content\">"+content+"</span>";
00195 text += "</div>";
00196 }
00197
00198 text += "<div class=\"body\">";
00199
00200 if (article.commentsLink().isValid())
00201 {
00202 text += "<a class=\"contentlink\" href=\"";
00203 text += article.commentsLink().url();
00204 text += "\">" + i18n( "Comments");
00205 if (article.comments())
00206 {
00207 text += " ("+ QString::number(article.comments()) +')';
00208 }
00209 text += "</a>";
00210 }
00211
00212 if (article.link().isValid() || (article.guidIsPermaLink() && KUrl(article.guid()).isValid()))
00213 {
00214 text += "<p><a class=\"contentlink\" href=\"";
00215
00216 if (article.link().isValid())
00217 {
00218 text += article.link().url();
00219 }
00220 else
00221 {
00222 text += article.guid();
00223 }
00224 text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00225 }
00226 text += "</div>";
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 return text;
00240 }
00241
00242 QString DefaultNormalViewFormatter::getCss() const
00243 {
00244 const QPalette & pal = QApplication::palette();
00245
00246
00247 QString css = QString (
00248 "<style type=\"text/css\">\n"
00249 "@media screen, print {"
00250 "body {\n"
00251 " font-family: \"%1\" ! important;\n"
00252 " font-size: %2 ! important;\n"
00253 " color: %3 ! important;\n"
00254 " background: %4 ! important;\n"
00255 "}\n\n")
00256 .arg( Settings::standardFont(),
00257 QString::number(pointsToPixel(Settings::mediumFontSize()))+"px",
00258 pal.color( QPalette::Text ).name(),
00259 pal.color( QPalette::Base ).name() );
00260 css += (
00261 "a {\n"
00262 + QString(" color: %1 ! important;\n")
00263 + QString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00264 + "}\n\n"
00265 +".headerbox {\n"
00266 +" background: %2 ! important;\n"
00267 +" color: %3 ! important;\n"
00268 +" border:1px solid #000;\n"
00269 +" margin-bottom: 10pt;\n"
00270 + "}\n\n")
00271 .arg( pal.color( QPalette::Link ).name(),
00272 pal.color( QPalette::Background ).name(),
00273 pal.color( QPalette::Text ).name() );
00274 css += QString(".headertitle a:link { color: %1 ! important;\n text-decoration: none ! important;\n }\n"
00275 ".headertitle a:visited { color: %1 ! important;\n text-decoration: none ! important;\n }\n"
00276 ".headertitle a:hover{ color: %1 ! important;\n text-decoration: none ! important;\n }\n"
00277 ".headertitle a:active { color: %1 ! important;\n text-decoration: none ! important;\n }\n" )
00278 .arg( pal.color( QPalette::HighlightedText ).name() );
00279 css += QString(
00280 ".headertitle {\n"
00281 " background: %1 ! important;\n"
00282 " padding:2px;\n"
00283 " color: %2 ! important;\n"
00284 " font-weight: bold;\n"
00285 " text-decoration: none ! important;\n"
00286 "}\n\n"
00287 ".header {\n"
00288 " font-weight: bold;\n"
00289 " padding:2px;\n"
00290 " margin-right: 5px;\n"
00291 " text-decoration: none ! important;\n"
00292 "}\n\n"
00293 ".headertext a {\n"
00294 " text-decoration: none ! important;\n"
00295 "}\n\n"
00296 ".headimage {\n"
00297 " float: right;\n"
00298 " margin-left: 5px;\n"
00299 "}\n\n").arg(
00300 pal.color( QPalette::Highlight ).name(),
00301 pal.color( QPalette::HighlightedText ).name() );
00302
00303 css += QString(
00304 "body { clear: none; }\n\n"
00305 ".content {\n"
00306 " display: block;\n"
00307 " margin-bottom: 6px;\n"
00308 "}\n\n"
00309
00310 ".content > P:first-child {\n margin-top: 1px; }\n"
00311 ".content > DIV:first-child {\n margin-top: 1px; }\n"
00312 ".content > BR:first-child {\n display: none; }\n"
00313
00314 "}\n\n"
00315
00316
00317 "\n\n");
00318
00319 return css;
00320 }
00321
00322 DefaultCombinedViewFormatter::DefaultCombinedViewFormatter(const KUrl& imageDir, QPaintDevice* device ) : ArticleFormatter( device ), m_imageDir(imageDir)
00323 {
00324 }
00325
00326 DefaultNormalViewFormatter::DefaultNormalViewFormatter(const KUrl& imageDir, QPaintDevice* device )
00327 : ArticleFormatter( device ),
00328 m_imageDir( imageDir ),
00329 m_summaryVisitor( new SummaryVisitor( this ) )
00330 {
00331 }
00332
00333 DefaultNormalViewFormatter::~DefaultNormalViewFormatter()
00334 {
00335 delete m_summaryVisitor;
00336 }
00337
00338 QString DefaultCombinedViewFormatter::formatArticle(const Article& article, IconOption icon) const
00339 {
00340 QString text;
00341 text = QString("<div class=\"headerbox\" dir=\"%1\">\n").arg(QApplication::isRightToLeft() ? "rtl" : "ltr");
00342
00343 if (!article.title().isEmpty())
00344 {
00345 text += QString("<div class=\"headertitle\" dir=\"%1\">\n").arg(Utils::directionOf(Utils::stripTags(article.title())));
00346 if (article.link().isValid())
00347 text += "<a href=\""+article.link().url()+"\">";
00348 text += article.title().replace("<", "<").replace(">", ">");
00349 if (article.link().isValid())
00350 text += "</a>";
00351 text += "</div>\n";
00352 }
00353 if (article.pubDate().isValid())
00354 {
00355 text += QString("<span class=\"header\" dir=\"%1\">").arg(Utils::directionOf(i18n("Date")));
00356 text += QString ("%1:").arg(i18n("Date"));
00357 text += "</span><span class=\"headertext\">";
00358 text += KGlobal::locale()->formatDateTime(article.pubDate(), KLocale::LongDate, false)+"</span>\n";
00359 }
00360
00361 const QString author = article.authorAsHtml();
00362 if (!author.isEmpty())
00363 {
00364 text += QString("<br/><span class=\"header\" dir=\"%1\">").arg(Utils::directionOf(i18n("Author")));
00365 text += QString ("%1:").arg(i18n("Author"));
00366 text += "</span><span class=\"headertext\">";
00367 text += author+"</span>\n";
00368 }
00369
00370 text += "</div>\n";
00371
00372 if (icon == ShowIcon && article.feed() && !article.feed()->image().isNull())
00373 {
00374 const Feed* feed = article.feed();
00375 QString file = Utils::fileNameForUrl(feed->xmlUrl());
00376 KUrl u(m_imageDir);
00377 u.setFileName(file);
00378 text += QString("<a href=\"%1\"><img class=\"headimage\" src=\"%2.png\"></a>\n").arg(feed->htmlUrl(), u.url());
00379 }
00380
00381
00382 const QString content = article.content( Article::DescriptionAsFallback );
00383 if (!content.isEmpty())
00384 {
00385 text += QString("<div dir=\"%1\">").arg(Utils::directionOf(Utils::stripTags(content)) );
00386 text += "<span class=\"content\">"+content+"</span>";
00387 text += "</div>";
00388 }
00389
00390 text += "<div class=\"body\">";
00391
00392 if (article.commentsLink().isValid())
00393 {
00394 text += "<a class=\"contentlink\" href=\"";
00395 text += article.commentsLink().url();
00396 text += "\">" + i18n( "Comments");
00397 if (article.comments())
00398 {
00399 text += " ("+ QString::number(article.comments()) +')';
00400 }
00401 text += "</a>";
00402 }
00403
00404 if (article.link().isValid() || (article.guidIsPermaLink() && KUrl(article.guid()).isValid()))
00405 {
00406 text += "<p><a class=\"contentlink\" href=\"";
00407
00408 if (article.link().isValid())
00409 {
00410 text += article.link().url();
00411 }
00412 else
00413 {
00414 text += article.guid();
00415 }
00416 text += "\">" + i18n( "Complete Story" ) + "</a></p>";
00417 }
00418 text += "</div>";
00419
00420 return text;
00421 }
00422
00423 QString DefaultCombinedViewFormatter::getCss() const
00424 {
00425 const QPalette &pal = QApplication::palette();
00426
00427
00428 QString css = QString (
00429 "<style type=\"text/css\">\n"
00430 "@media screen, print {"
00431 "body {\n"
00432 " font-family: \"%1\" ! important;\n"
00433 " font-size: %2 ! important;\n"
00434 " color: %3 ! important;\n"
00435 " background: %4 ! important;\n"
00436 "}\n\n").arg(Settings::standardFont(),
00437 QString::number(pointsToPixel(Settings::mediumFontSize()))+"px",
00438 pal.color( QPalette::Text ).name(),
00439 pal.color( QPalette::Base ).name() );
00440 css += (
00441 "a {\n"
00442 + QString(" color: %1 ! important;\n")
00443 + QString(!Settings::underlineLinks() ? " text-decoration: none ! important;\n" : "")
00444 + "}\n\n"
00445 +".headerbox {\n"
00446 +" background: %2 ! important;\n"
00447 +" color: %3 ! important;\n"
00448 +" border:1px solid #000;\n"
00449 +" margin-bottom: 10pt;\n"
00450
00451 + "}\n\n")
00452 .arg( pal.color( QPalette::Link ).name(),
00453 pal.color( QPalette::Background ).name(),
00454 pal.color( QPalette::Text ).name() );
00455
00456 css += QString(".headertitle a:link { color: %1 ! important; text-decoration: none ! important;\n }\n"
00457 ".headertitle a:visited { color: %1 ! important; text-decoration: none ! important;\n }\n"
00458 ".headertitle a:hover{ color: %1 ! important; text-decoration: none ! important;\n }\n"
00459 ".headertitle a:active { color: %1 ! important; text-decoration: none ! important;\n }\n")
00460 .arg( pal.color( QPalette::HighlightedText ).name() );
00461 css += QString(
00462 ".headertitle {\n"
00463 " background: %1 ! important;\n"
00464 " padding:2px;\n"
00465 " color: %2 ! important;\n"
00466 " font-weight: bold;\n"
00467 " text-decoration: none ! important;\n"
00468 "}\n\n"
00469 ".header {\n"
00470 " font-weight: bold;\n"
00471 " padding:2px;\n"
00472 " margin-right: 5px;\n"
00473 " text-decoration: none ! important;\n"
00474 "}\n\n"
00475 ".headertext {\n"
00476 " text-decoration: none ! important;\n"
00477 "}\n\n"
00478 ".headimage {\n"
00479 " float: right;\n"
00480 " margin-left: 5px;\n"
00481 "}\n\n").arg( pal.color( QPalette::Highlight ).name(),
00482 pal.color( QPalette::HighlightedText ).name() );
00483
00484 css += QString(
00485 "body { clear: none; }\n\n"
00486 ".content {\n"
00487 " display: block;\n"
00488 " margin-bottom: 6px;\n"
00489 "}\n\n"
00490
00491 ".content > P:first-child {\n margin-top: 1px; }\n"
00492 ".content > DIV:first-child {\n margin-top: 1px; }\n"
00493 ".content > BR:first-child {\n display: none; }\n"
00494
00495 "}\n\n"
00496
00497
00498 "\n\n");
00499
00500 return css;
00501 }
00502
00503 QString DefaultNormalViewFormatter::formatSummary(TreeNode* node) const
00504 {
00505 return m_summaryVisitor->formatSummary(node);
00506 }
00507
00508 QString DefaultCombinedViewFormatter::formatSummary(TreeNode*) const
00509 {
00510 return QString();
00511 }
00512
00513 }