/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Eclipse Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.ui.internal.editors.feed; import static org.rssowl.ui.internal.ILinkHandler.HANDLER_PROTOCOL; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.ARCHIVE_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.ATTACHMENTS_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.ATTACHMENT_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.COLLAPSE_GROUP_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.COLLAPSE_NEWS_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.DELETE_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.EXPAND_NEWS_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.GROUP_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.LABELS_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.NEWS_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.NEXT_PAGE_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.RELATED_NEWS_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.SHARE_NEWS_MENU_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.TOGGLE_READ_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.TOGGLE_STICKY_HANDLER_ID; import static org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.TRANSFORM_HANDLER_ID; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.PlatformUI; import org.rssowl.core.Owl; import org.rssowl.core.internal.persist.pref.DefaultPreferences; import org.rssowl.core.persist.IAttachment; import org.rssowl.core.persist.IBookMark; import org.rssowl.core.persist.ILabel; import org.rssowl.core.persist.INews; import org.rssowl.core.persist.INews.State; import org.rssowl.core.persist.IPerson; import org.rssowl.core.persist.ISource; import org.rssowl.core.persist.reference.NewsBinReference; import org.rssowl.core.persist.reference.NewsReference; import org.rssowl.core.persist.reference.SearchMarkReference; import org.rssowl.core.util.CoreUtils; import org.rssowl.core.util.DateUtils; import org.rssowl.core.util.ExpandingReader; import org.rssowl.core.util.StringUtils; import org.rssowl.core.util.URIUtils; import org.rssowl.ui.internal.Activator; import org.rssowl.ui.internal.Application; import org.rssowl.ui.internal.ApplicationServer; import org.rssowl.ui.internal.EntityGroup; import org.rssowl.ui.internal.FolderNewsMark.FolderNewsMarkReference; import org.rssowl.ui.internal.OwlUI; import org.rssowl.ui.internal.editors.feed.NewsBrowserViewer.PageLatch; import org.rssowl.ui.internal.util.CBrowser; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.net.URI; import java.text.DateFormat; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * @author bpasero */ public class NewsBrowserLabelProvider extends LabelProvider { /* Date Formatter for News */ private DateFormat fDateFormat = OwlUI.getLongDateFormat(); /* Time Formatter for News */ private DateFormat fTimeFormat = OwlUI.getShortTimeFormat(); /* Potential Image Tags */ private final Set<String> fImageTags = new HashSet<String>(Arrays.asList(new String[] { "img", "map", "area" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ /* Potential Media Tags */ private final Set<String> fMediaTags = new HashSet<String>(Arrays.asList(new String[] { "applet", "embed", "frame", "frameset", "iframe", "object" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ /* Image and Media Tags */ private final Set<String> fImageAndMediaTags; /* Windows only: Mark of the Web */ private static final String IE_MOTW = "<!-- saved from url=(0014)about:internet -->"; //$NON-NLS-1$ /* Dynamic HTML in Content */ enum Dynamic { NEWS("newsitem"), //$NON-NLS-1$ GROUP("group"), //$NON-NLS-1$ GROUP_NOTE("groupNote"), //$NON-NLS-1$ TITLE("title"), //$NON-NLS-1$ TITLE_LINK("titleLink"), //$NON-NLS-1$ SUBTITLE_LINK("subtitleLink"), //$NON-NLS-1$ SUBLINE("subline"), //$NON-NLS-1$ DELETE("delete"), //$NON-NLS-1$ TOGGLE_READ_LINK("toggleRead"), //$NON-NLS-1$ TOGGLE_READ_IMG("toggleReadImg"), //$NON-NLS-1$ TINY_TOGGLE_STICKY_LINK("tinyToggleStickyLink"), //$NON-NLS-1$ TOGGLE_STICKY_LINK("toggleStickyLink"), //$NON-NLS-1$ TOGGLE_STICKY_IMG("toggleStickyImg"), //$NON-NLS-1$ TOGGLE_GROUP_LINK("toggleGroupLink"), //$NON-NLS-1$ TOGGLE_GROUP_IMG("toggleGroupImg"), //$NON-NLS-1$ LABELS_MENU_LINK("labelsMenuLink"), //$NON-NLS-1$ ARCHIVE_LINK("archiveLink"), //$NON-NLS-1$ SHARE_MENU_LINK("shareMenuLink"), //$NON-NLS-1$ GROUP_MENU_LINK("groupMenuLink"), //$NON-NLS-1$ NEWS_MENU_LINK("newsMenuLink"), //$NON-NLS-1$ HEADER("header"), //$NON-NLS-1$ CONTENT("content"), //$NON-NLS-1$ FOOTER("footer"), //$NON-NLS-1$ FOOTER_STICKY_LINK("footerStickyLink"), //$NON-NLS-1$ FOOTER_ARCHIVE_LINK("footerArchiveLink"), //$NON-NLS-1$ FOOTER_LABEL_MENU_LINK("footerLabelMenuLink"), //$NON-NLS-1$ FOOTER_SHARE_MENU_LINK("footerShareMenuLink"), //$NON-NLS-1$ FIND_RELATED_MENU_LINK("findRelatedMenuLink"), //$NON-NLS-1$ FOOTER_NEWS_MENU_LINK("footerNewsMenuLink"), //$NON-NLS-1$ ATTACHMENTS_MENU_LINK("attachmentsMenuLink"), //$NON-NLS-1$ ATTACHMENT_LINK("attachmentLink"), //$NON-NLS-1$ COLLAPSE_LINK("collapseLink"), //$NON-NLS-1$ FULL_CONTENT_LINK("fullContentLink"), //$NON-NLS-1$ FULL_CONTENT_LINK_TEXT("fullContentLinkText"), //$NON-NLS-1$ LABELS("labels"), //$NON-NLS-1$ LABELS_SEPARATOR("labelsSeparator"), //$NON-NLS-1$ HEADLINE_SEPARATOR("headlineSeparator"), //$NON-NLS-1$ PAGE_LATCH("pageLatch"), //$NON-NLS-1$ PAGE_LATCH_LINK("pageLatchLink"), //$NON-NLS-1$ PAGE_LATCH_TEXT("pageLatchText"); //$NON-NLS-1$ private String fId; Dynamic(String id) { fId = id; } String getId() { return fId; } String getId(long id) { return fId + id; } String getId(EntityGroup group) { return fId + group.getId(); } String getId(INews news) { return fId + news.getId(); } String getId(NewsReference newsRef) { return fId + newsRef.getId(); } } /* Colors and Fonts */ private String fNewsFontFamily; private String fNormalFontCSS; private String fVerySmallFontCSS; private String fSmallFontCSS; private String fBiggerFontCSS; private String fBiggestFontCSS; private String fStickyBGColorCSS; private String fNewsListBGColorCSS; private String fLinkFGColorCSS; private boolean fIsNewsListBGColorDefined; private IPropertyChangeListener fPropertyChangeListener; /* Label Provider State */ private final NewsBrowserViewer fViewer; private final boolean fIsIE; private boolean fStripImagesFromNews; private boolean fStripMediaFromNews; private boolean fForceShowFeedInformation; private boolean fManageLinks; private boolean fShowFooter; private boolean fHeadlinesOnly; private boolean fForceNoGrouping; private boolean fForceNoPaging; private final long fTodayInMillies; private final Map<String, String> fMapFeedLinkToName = new HashMap<String, String>(); /** * Creates a new Browser LabelProvider for News * * @param browser */ public NewsBrowserLabelProvider(CBrowser browser) { this(null, browser.isIE()); } /** * Creates a new Browser LabelProvider for News * * @param viewer */ public NewsBrowserLabelProvider(NewsBrowserViewer viewer) { this(viewer, viewer.getBrowser().isIE()); } private NewsBrowserLabelProvider(NewsBrowserViewer viewer, boolean isIE) { fViewer = viewer; fIsIE = isIE; fManageLinks = OwlUI.useExternalBrowser() || Owl.getPreferenceService().getGlobalScope().getBoolean(DefaultPreferences.OPEN_LINKS_IN_NEW_TAB); fShowFooter = true; fTodayInMillies = DateUtils.getToday().getTimeInMillis(); fImageAndMediaTags = new HashSet<String>(); fImageAndMediaTags.addAll(fImageTags); fImageAndMediaTags.addAll(fMediaTags); createFonts(); createColors(); registerListeners(); } /** * @param stripImagesFromNews <code>true</code> to strip images from the news * and <code>false</code> otherwise. * @param stripMediaFromNews <code>true</code> to strip media from the news * and <code>false</code> otherwise. */ public void setStripMediaFromNews(boolean stripImagesFromNews, boolean stripMediaFromNews) { fStripImagesFromNews = stripImagesFromNews; fStripMediaFromNews = stripMediaFromNews; } /* Removes Media Tags from the provided String if the provider is configured to do so */ String stripMediaTagsIfNecessary(String str) { if (fStripImagesFromNews && fStripMediaFromNews) return StringUtils.filterTags(str, fImageAndMediaTags, false); else if (fStripImagesFromNews) return StringUtils.filterTags(str, fImageTags, false); else if (fStripMediaFromNews) return StringUtils.filterTags(str, fMediaTags, false); return str; } /* Highlight search terms if any */ String highlightSearchTermsIfNecessary(String str) { if (fViewer != null) { Collection<String> wordsToHighlight = fViewer.getHighlightedWords(); if (!wordsToHighlight.isEmpty()) { StringBuilder highlightedResult = new StringBuilder(str.length()); RGB searchRGB = OwlUI.getThemeRGB(OwlUI.SEARCH_HIGHLIGHT_BG_COLOR_ID, new RGB(255, 255, 0)); String preHighlight = "<span style=\"background-color:rgb(" + OwlUI.toString(searchRGB) + ");\">"; //$NON-NLS-1$ //$NON-NLS-2$ String postHighlight = "</span>"; //$NON-NLS-1$ ExpandingReader resultHighlightReader = new ExpandingReader(new StringReader(str), wordsToHighlight, preHighlight, postHighlight, true); int len = 0; char[] buf = new char[1000]; try { while ((len = resultHighlightReader.read(buf)) != -1) highlightedResult.append(buf, 0, len); return highlightedResult.toString(); } catch (IOException e) { Activator.getDefault().logError(e.getMessage(), e); } } } return str; } /** * @param forceShowFeedInformation if <code>true</code> will show the name of * a feed of a news when shown, <code>false</code> otherwise. */ public void setForceShowFeedInformation(boolean forceShowFeedInformation) { fForceShowFeedInformation = forceShowFeedInformation; } /** * @param showFooter if <code>true</code> will show the footer for each news * and <code>false</code> otheriwse. Default is <code>true</code>. */ public void setShowFooter(boolean showFooter) { fShowFooter = showFooter; } /** * @param headlinesOnly if set to <code>true</code> only show headlines of * news and not the content, <code>false</code> otherwise. Default is * <code>false</code>. */ public void setHeadlinesOnly(boolean headlinesOnly) { fHeadlinesOnly = headlinesOnly; } boolean isHeadlinesOnly() { return fHeadlinesOnly; } /* * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose() */ @Override public void dispose() { super.dispose(); unregisterListeners(); fMapFeedLinkToName.clear(); } private void registerListeners() { /* Create Property Listener */ fPropertyChangeListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { String property = event.getProperty(); if (OwlUI.NEWS_TEXT_FONT_ID.equals(property)) createFonts(); else if (OwlUI.STICKY_BG_COLOR_ID.equals(property) || OwlUI.LINK_FG_COLOR_ID.equals(property) || OwlUI.NEWS_LIST_BG_COLOR_ID.equals(property)) createColors(); } }; /* Add it to listen to Theme Events */ PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(fPropertyChangeListener); } private void unregisterListeners() { PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(fPropertyChangeListener); } /* Init the Theme Font (from UI Thread) */ private void createFonts() { int fontHeight = 10; Font newsFont = OwlUI.getThemeFont(OwlUI.NEWS_TEXT_FONT_ID, SWT.NORMAL); FontData[] fontData = newsFont.getFontData(); if (fontData.length > 0) { fNewsFontFamily = fontData[0].getName(); fontHeight = fontData[0].getHeight(); } int normal = fontHeight; int verysmall = normal - 2; int small = normal - 1; int bigger = normal + 1; int biggest = bigger + 2; String fontUnit = "pt"; //$NON-NLS-1$ fNormalFontCSS = "font-size: " + normal + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$ fVerySmallFontCSS = "font-size: " + verysmall + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$ fSmallFontCSS = "font-size: " + small + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$ fBiggerFontCSS = "font-size: " + bigger + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$ fBiggestFontCSS = "font-size: " + biggest + fontUnit + ";"; //$NON-NLS-1$ //$NON-NLS-2$ } /* Init the Theme Color (from UI Thread) */ private void createColors() { RGB stickyRgb = OwlUI.getThemeRGB(OwlUI.STICKY_BG_COLOR_ID, new RGB(255, 255, 180)); fStickyBGColorCSS = "background-color: rgb(" + stickyRgb.red + "," + stickyRgb.green + "," + stickyRgb.blue + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ RGB linkRgb = OwlUI.getThemeRGB(OwlUI.LINK_FG_COLOR_ID, new RGB(0, 0, 153)); fLinkFGColorCSS = "color: rgb(" + linkRgb.red + "," + linkRgb.green + "," + linkRgb.blue + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ RGB newsListRgb = OwlUI.getThemeRGB(OwlUI.NEWS_LIST_BG_COLOR_ID, new RGB(255, 255, 255)); fNewsListBGColorCSS = "background-color: rgb(" + newsListRgb.red + "," + newsListRgb.green + "," + newsListRgb.blue + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ fIsNewsListBGColorDefined = !newsListRgb.equals(new RGB(255, 255, 255)); } /* * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) */ @Override public String getText(Object element) { return getText(element, true, true, -1); } /** * @param element the element to get a HTML representation from. * @param withInternalLinks <code>true</code> to include links of the internal * protocol rssowl:// and <code>false</code> otherwise. * @param withManagedLinks if set to <code>false</code>, the output will not * contain any managed links. * @param index the zero-based index of the element from top. * @return the HTML representation for the given element. */ public String getText(Object element, boolean withInternalLinks, boolean withManagedLinks, int index) { /* Return HTML for a Group */ if (element instanceof EntityGroup) return getLabel((EntityGroup) element, withInternalLinks); /* Return HTML for a News */ else if (element instanceof INews) return getLabel((INews) element, withInternalLinks, withManagedLinks, false, index); /* Return HTML for Page Latch */ else if (element instanceof PageLatch) return getLabel((PageLatch) element); return ""; //$NON-NLS-1$ } private boolean isSingleNewsDisplayed() { Object input = fViewer != null ? fViewer.getInput() : null; return input instanceof INews; } private boolean isEntityGroupDisplayed() { Object input = fViewer != null ? fViewer.getInput() : null; return input instanceof EntityGroup; } private boolean isGroupingEnabled() { if (isEntityGroupDisplayed()) return false; //Entity Group as input does not count here if (fForceNoGrouping) return false; //Special case where content is rendered for outside the application if (fViewer != null) { IContentProvider cp = fViewer.getContentProvider(); if (cp instanceof NewsContentProvider) return ((NewsContentProvider) cp).isGroupingEnabled(); } return false; } private boolean showFeedInformation() { if (fForceShowFeedInformation) return true; Object input = fViewer != null ? fViewer.getInput() : null; return input instanceof FolderNewsMarkReference || input instanceof SearchMarkReference || input instanceof NewsBinReference; } /** * Writes the CSS information to the given Writer. * * @param writer the writer to add the CSS information to. * @throws IOException In case of an error while writing. */ public void writeCSS(Writer writer) throws IOException { writeCSS(writer, isSingleNewsDisplayed(), true); } /** * Writes the CSS information to the given Writer. * * @param writer the writer to add the CSS information to. * @param forSingleNews if <code>true</code>, the site contains a single news, * or <code>false</code> if it contains a collection of news. * @param withInternalLinks <code>true</code> to include links of the internal * protocol rssowl:// and <code>false</code> otherwise. * @throws IOException In case of an error while writing. */ public void writeCSS(Writer writer, boolean forSingleNews, boolean withInternalLinks) throws IOException { boolean isGroupingEnabled = isGroupingEnabled(); /* Open CSS */ writer.write("<style type=\"text/css\">\n"); //$NON-NLS-1$ /* Common CSS Rules */ writeCommonCSS(writer, forSingleNews, withInternalLinks); /* Common Headlines Layout Rules */ if (fHeadlinesOnly) writeCommonHeadlinesCSS(writer); /* Common Newspaper Layout Rules */ else writeCommonNewspaperCSS(writer); /* Single News */ if (forSingleNews) writesingleNewsCSS(writer); /* Headlines Grouped */ else if (isGroupingEnabled && fHeadlinesOnly) writeHeadlinesGroupedCSS(writer); /* Newspaper Grouped */ else if (isGroupingEnabled && !fHeadlinesOnly) writeNewspaperGroupedCSS(writer); /* Headlines Ungrouped */ else if (!isGroupingEnabled && fHeadlinesOnly) writeHeadlinesUngroupedCSS(writer); /* Newspaper Ungrouped */ else if (!isGroupingEnabled && !fHeadlinesOnly) writeNewspaperUngroupedCSS(writer); writer.write("</style>\n"); //$NON-NLS-1$ } /* Common CSS in all Layouts */ private void writeCommonCSS(Writer writer, boolean forSingleNews, boolean withInternalLinks) throws IOException { /* General */ writer.append("body { overflow: auto; margin: 0; font-family: ").append(fNewsFontFamily).append(",Verdanna,sans-serif; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a { ").append(fLinkFGColorCSS).append(" text-decoration: none; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a:hover { ").append(fLinkFGColorCSS).append(" text-decoration: underline; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a:visited { ").append(fLinkFGColorCSS).append(" text-decoration: none; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("img { border: none; }\n"); //$NON-NLS-1$ writer.append("div.hidden { display: none; }\n"); //$NON-NLS-1$ /* Group */ writer.append("div.group { color: #678; ").append(fBiggestFontCSS).append(" font-weight: bold; margin: 10px 0px 5px 5px; padding-bottom: 3px; border-bottom: 1px solid #678; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.group a { color: #678; ").append(fBiggestFontCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.group a:hover { color: #678; ").append(fBiggestFontCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.group a:visited { color: #678; ").append(fBiggestFontCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("span.groupNote { margin-left: 5px; ").append(fNormalFontCSS).append(" font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Content */ writer.append("div.content { \n"); //$NON-NLS-1$ writer.append(" padding: 15px 10px 15px 10px; border-top: dotted 1px silver; \n"); //$NON-NLS-1$ writer.append(" background-color: #fff; clear: both; ").append(fNormalFontCSS).append(" font-style: normal; \n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("}\n"); //$NON-NLS-1$ /* Restrict the style of embedded Paragraphs */ writer.write("div.content p { margin-top: 0 !important; padding-top: 0 !important; margin-left: 0 !important; padding-left: 0 !important; }\n"); //$NON-NLS-1$ /* Title */ if (!withInternalLinks) writer.append("div.title { float: left; ").append(fBiggerFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.title span.unread { font-weight: bold; }\n"); //$NON-NLS-1$ /* Author */ writer.append("div.author { text-align: right; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a.author { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("a.author:hover { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("a.author:active { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("a.author:visited { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ /* Comments */ writer.write("a.comments { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.write("a.comments:hover { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.write("a.comments:active { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.write("a.comments:visited { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ /* Subline */ writer.append("table.subline { margin: 0; padding: 0; }\n"); //$NON-NLS-1$ writer.append("tr.subline { margin: 0; padding: 0; }\n"); //$NON-NLS-1$ writer.append("td.firstactionsubline { text-align: left; width: 20px; margin: 0; padding: 0; color: rgb(80, 80, 80); ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("td.firstactionsubline a { width: 20px; }\n"); //$NON-NLS-1$ writer.append("td.otheractionsubline { text-align: center; width: 22px; margin: 0; padding: 0; color: rgb(80, 80, 80); ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("td.otheractionsubline a { width: 22px; }\n"); //$NON-NLS-1$ writer.append("td.subline { margin: 0; padding: 0; color: rgb(80, 80, 80); padding-right: 5px; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("td.sublineseparator { margin: 0; padding: 0; color: rgb(140, 140, 140); padding-right: 5px; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("td.actionsublineseparator { margin: 0; padding: 0; color: rgb(140, 140, 140); padding-left: 4px; padding-right: 5px; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Date */ writer.append("div.date { float: left; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Footer Line */ writer.append("div.footerline { clear: both; ").append(fVerySmallFontCSS).append(" padding-left: 3px; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.footerline a { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("div.footerline a:visited { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("div.footerline a:hover { color: rgb(80,80,80); text-decoration: none; }\n"); //$NON-NLS-1$ writer.append("table.footerline { margin: 0; padding: 0; }\n"); //$NON-NLS-1$ writer.append("tr.footerline { margin: 0; padding: 0; }\n"); //$NON-NLS-1$ writer.append("td.footerline { margin: 0; padding: 0; padding-right: 5px; ").append(fVerySmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("td.footerlineseparator { margin: 0; padding: 0; color: rgb(140, 140, 140); padding-right: 5px; ").append(fVerySmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Clearing Footer */ if (!forSingleNews) writer.write("div.clearingFooter { clear: both; }\n"); //$NON-NLS-1$ /* Quotes */ writer.write("span.quote_lvl1 { color: #660066; }\n"); //$NON-NLS-1$ writer.write("span.quote_lvl2 { color: #007777; }\n"); //$NON-NLS-1$ writer.write("span.quote_lvl3 { color: #3377ff; }\n"); //$NON-NLS-1$ writer.write("span.quote_lvl4 { color: #669966; }\n"); //$NON-NLS-1$ /* Page Latch */ writer.append("div.pageLatch { padding: 5px; text-align: center; ").append(fNormalFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.pageLatch a { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.pageLatch a:hover { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.pageLatch a:active { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.pageLatch a:visited { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Common CSS for Headlines Layout */ private void writeCommonHeadlinesCSS(Writer writer) throws IOException { /* Title (Collapsed - Initially) */ writer.append("div.title { ").append(fNormalFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.title a { color: black; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.title a.unread { font-weight: bold; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.title a:hover { color: black; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.title a:visited { color: black; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ /* Title (Expanded) */ writer.append("div.titleExpanded { width: 90%; float: left; ").append(fBiggerFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.titleExpanded a { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.titleExpanded a.unread { font-weight: bold; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.titleExpanded a:hover { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.titleExpanded a:visited { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Title (Collapsed - By user) */ writer.append("div.titleCollapsed { ").append(fNormalFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.titleCollapsed a { color: rgb(80, 80, 80); text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.titleCollapsed a.unread { color: rgb(80, 80, 80); font-weight: bold; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.titleCollapsed a:hover { color: rgb(80, 80, 80); text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.titleCollapsed a:visited { color: rgb(80, 80, 80); text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ /* Subtitle */ writer.append("a.subtitle { font-style: italic !important; text-decoration: none; padding-left: 10px; color: rgb(80, 80, 80); ").append(fVerySmallFontCSS).append(" }"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a.subtitle:hover { font-style: italic !important; text-decoration: none; padding-left: 10px; color: rgb(80, 80, 80); ").append(fVerySmallFontCSS).append(" }"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("a.subtitle:visited { font-style: italic !important; text-decoration: none; padding-left: 10px; color: rgb(80, 80, 80); ").append(fVerySmallFontCSS).append(" }"); //$NON-NLS-1$ //$NON-NLS-2$ /* Delete */ writer.append("div.delete { padding-top: 5px; text-align: right; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Subline */ writer.append("div.subline { margin: 8px 0px 0px 0px; padding: 0; clear: left; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Footer */ writer.append(" div.footer { padding: 3px 5px 5px 5px; line-height: 20px; border-top: dotted 1px silver; clear: both; }\n"); //$NON-NLS-1$ writer.append("div.footerSticky { padding: 3px 5px 5px 5px; line-height: 20px; border-top: dotted 1px silver; clear: both; ").append(fStickyBGColorCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Common CSS for Newspaper Layout */ private void writeCommonNewspaperCSS(Writer writer) throws IOException { /* Title */ writer.append("div.title { width: 90%; float: left; padding-bottom: 6px; ").append(fBiggerFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.title a { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.title a.unread { font-weight: bold; text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ writer.append("div.title a:hover { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.append("div.title a:visited { ").append(fLinkFGColorCSS).append(" text-decoration: none; font-style: normal; }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Delete */ writer.append("div.delete { text-align: right; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Subline */ writer.append("div.subline { margin: 0; padding: 0; clear: left; ").append(fSmallFontCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Footer */ writer.append(" div.footer { padding: 3px 5px 3px 5px; line-height: 20px; border-top: dotted 1px silver; border-bottom: 1px solid white; clear: both; }\n"); //$NON-NLS-1$ writer.append("div.footerSticky { padding: 3px 5px 3px 5px; line-height: 20px; border-top: dotted 1px silver; border-bottom: 1px dotted silver; clear: both; ").append(fStickyBGColorCSS).append("}\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Single News */ private void writesingleNewsCSS(Writer writer) throws IOException { /* News Container */ writer.write(" div.newsitemRead { margin: 0; }\n"); //$NON-NLS-1$ writer.write("div.newsitemUnread { margin: 0; }\n"); //$NON-NLS-1$ /* Header */ writer.append(" div.header { padding: 10px 10px 5px 10px; background-color: rgb(242,242,242); }\n"); //$NON-NLS-1$ writer.append("div.headerSticky { padding: 10px 10px 5px 10px; ").append(fStickyBGColorCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ writer.write(" div.footer { padding: 3px 5px 3px 5px; line-height: 20px; border-top: dotted 1px silver; border-bottom: dotted 1px silver; clear: both; background-color: rgb(248,248,248); }\n"); //$NON-NLS-1$ writer.append("div.footerSticky { padding: 3px 5px 3px 5px; line-height: 20px; border-top: dotted 1px silver; border-bottom: dotted 1px silver; clear: both; ").append(fStickyBGColorCSS).append("}\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Newspaper Ungrouped */ private void writeNewspaperUngroupedCSS(Writer writer) throws IOException { /* News Container */ writer.write("div.newsitemRead { margin: 0px 0px 10px 0px; border-bottom: 1px solid white; }\n"); //$NON-NLS-1$ writer.write("div.newsitemUnread { margin: 0px 0px 10px 0px; border-bottom: 1px solid white; }\n"); //$NON-NLS-1$ /* Header */ writer.append(" div.header { padding: 10px 10px 5px 10px; border-top: 1px solid white; }\n"); //$NON-NLS-1$ writer.append("div.headerSticky { padding: 10px 10px 5px 10px; border-top: 1px dotted silver; ").append(fStickyBGColorCSS).append("}\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Newspaper Grouped */ private void writeNewspaperGroupedCSS(Writer writer) throws IOException { /* News Container */ writer.write(" div.newsitemRead { margin: 0px 0px 10px 10px; border-bottom: 1px solid white; }\n"); //$NON-NLS-1$ writer.write("div.newsitemUnread { margin: 0px 0px 10px 10px; border-bottom: 1px solid white; }\n"); //$NON-NLS-1$ /* Header */ writer.append(" div.header { padding: 10px 10px 5px 10px; border-top: 1px solid white; }\n"); //$NON-NLS-1$ writer.append("div.headerSticky { padding: 10px 10px 5px 10px; border-top: 1px dotted silver; ").append(fStickyBGColorCSS).append("}\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Headlines Ungrouped */ private void writeHeadlinesUngroupedCSS(Writer writer) throws IOException { /* News Container */ writer.write(" div.newsitemRead { margin: 0px 0px 0px 0px; }\n"); //$NON-NLS-1$ writer.write("div.newsitemUnread { margin: 0px 0px 0px 0px; }\n"); //$NON-NLS-1$ /* Header */ writer.write(" div.header { padding: 5px 10px 5px 10px; }\n"); //$NON-NLS-1$ writer.append("div.headerSticky { padding: 5px 10px 5px 10px; ").append(fStickyBGColorCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Headlines Separator */ writer.append("div.headlinesSeparator { margin: 0; padding: 0; border-bottom: 1px dotted silver; }\n"); //$NON-NLS-1$ } /* Headlines Grouped */ private void writeHeadlinesGroupedCSS(Writer writer) throws IOException { /* News Container */ writer.write(" div.newsitemRead { margin: 0px 0px 0px 10px; }\n"); //$NON-NLS-1$ writer.write("div.newsitemUnread { margin: 0px 0px 0px 10px; }\n"); //$NON-NLS-1$ /* Header */ writer.write(" div.header { padding: 5px 10px 5px 10px; }\n"); //$NON-NLS-1$ writer.append("div.headerSticky { padding: 5px 10px 5px 10px; ").append(fStickyBGColorCSS).append(" }\n"); //$NON-NLS-1$ //$NON-NLS-2$ /* Headlines Separator */ writer.append("div.headlinesSeparator { margin: 0px 0px 0px 10px; padding: 0; border-bottom: 1px dotted silver; }\n"); //$NON-NLS-1$ } private String getLabel(EntityGroup group, boolean withInternalLinks) { boolean isVisible = isVisible(group); StringBuilder builder = new StringBuilder(); String groupName = StringUtils.htmlEscape(group.getName()); String groupColor = null; if (group.getColorHint() != null && !group.getColorHint().equals(new RGB(255, 255, 255))) groupColor = OwlUI.toString(group.getColorHint()); /* DIV: Group */ StringBuilder extraCSS = new StringBuilder(); if (!isVisible) extraCSS.append("display: none; "); //$NON-NLS-1$ if (groupColor != null) extraCSS.append("border-bottom-color: rgb(" + groupColor + ");"); //$NON-NLS-1$ //$NON-NLS-2$ if (extraCSS.length() == 0) div(builder, "group", Dynamic.GROUP.getId(group)); //$NON-NLS-1$ else div(builder, "group", extraCSS.toString(), Dynamic.GROUP.getId(group)); //$NON-NLS-1$ /* Let the group name be a link to invoke actions on all news inside and provide a toggle */ if (withInternalLinks) { /* Toggle to Expand / Collapse */ String link = HANDLER_PROTOCOL + COLLAPSE_GROUP_HANDLER_ID + "?" + group.getId(); //$NON-NLS-1$ imageLink(builder, link, null, null, "/icons/elcl16/expanded.gif", "expanded.gif", Dynamic.TOGGLE_GROUP_LINK.getId(group), Dynamic.TOGGLE_GROUP_IMG.getId(group)); //$NON-NLS-1$ //$NON-NLS-2$ /* Group Name as Link */ link = HANDLER_PROTOCOL + GROUP_MENU_HANDLER_ID + "?" + group.getId(); //$NON-NLS-1$ link(builder, link, groupName, null, Dynamic.GROUP_MENU_LINK.getId(group), groupColor); } /* Not using internal links */ else { span(builder, groupName, null, groupColor); } /* Group Note (number of articles and filtered elements if any) */ int actualSize = group.getSizeHint(); int totalSize = group.getEntities().size(); String groupNote = getGroupNote(actualSize, totalSize); span(builder, groupNote, "groupNote", Dynamic.GROUP_NOTE.getId(group), groupColor); //$NON-NLS-1$ /* Close: Group */ close(builder, "div"); //$NON-NLS-1$ return builder.toString(); } String getGroupNote(int actualSize, int totalSize) { int sizeDiff = totalSize - actualSize; String groupNote; if (actualSize == 1) { if (sizeDiff == 0) groupNote = Messages.NewsBrowserLabelProvider_ONE_ARTICLE; else groupNote = NLS.bind(Messages.NewsBrowserLabelProvider_ONE_ARTICLE_N_FILTERED, sizeDiff); } else { if (sizeDiff == 0) groupNote = NLS.bind(Messages.NewsBrowserLabelProvider_N_ARTICLES, actualSize); else groupNote = NLS.bind(Messages.NewsBrowserLabelProvider_N_ARTICLES_M_FILTERED, actualSize, sizeDiff); } return groupNote; } private StringBuilder getBuilder(INews news, String description) { int capacity = 0; if (news.getTitle() != null) capacity += news.getTitle().length(); if (description != null) capacity += description.length(); return new StringBuilder(capacity); } String getLabel(INews news, boolean withInternalLinks, boolean withManagedLinks, boolean onlyInnerContent, int index) { boolean isVisible = isVisible(news) || fForceNoPaging; String description = null; //Fetch description lazily if only headlines shown or news hidden if (!fHeadlinesOnly && isVisible) description = stripMediaTagsIfNecessary(news.getDescription()); StringBuilder builder = getBuilder(news, description); State state = news.getState(); boolean isUnread = (state == State.NEW || state == State.UPDATED || state == State.UNREAD); /* DIV: NewsItem (as needed) */ if (!onlyInnerContent) { StringBuilder extraCSS = new StringBuilder(); if (!isVisible) extraCSS.append("display: none; "); //$NON-NLS-1$ if (index != 0 && fIsNewsListBGColorDefined && index % 2 != 0) extraCSS.append(fNewsListBGColorCSS); if (extraCSS.length() != 0) div(builder, isUnread ? "newsitemUnread" : "newsitemRead", extraCSS.toString(), Dynamic.NEWS.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ else div(builder, isUnread ? "newsitemUnread" : "newsitemRead", Dynamic.NEWS.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ } /* Full content of News only added if the news is actually visible */ if (isVisible) { String newsTitle = CoreUtils.getHeadline(news, false); String newsLink = CoreUtils.getLink(news); boolean hasLink = newsLink != null; Set<ILabel> labels = CoreUtils.getSortedLabels(news); String color = !labels.isEmpty() ? labels.iterator().next().getColor() : null; if ("0,0,0".equals(color) || "255,255,255".equals(color)) //Don't let black or white override link color //$NON-NLS-1$ //$NON-NLS-2$ color = null; /* DIV: NewsItem/Header */ if (index == 0) div(builder, news.isFlagged() ? "headerSticky" : "header", "border-top: none;", Dynamic.HEADER.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ else div(builder, news.isFlagged() ? "headerSticky" : "header", Dynamic.HEADER.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ /* News Title */ { /* DIV: NewsItem/Header/Title */ div(builder, "title", Dynamic.TITLE.getId(news)); //$NON-NLS-1$ String cssClass = isUnread ? "unread" : "read"; //$NON-NLS-1$ //$NON-NLS-2$ /* Collapsed Title Bar */ if (fHeadlinesOnly) { /* Make Sticky */ String link = HANDLER_PROTOCOL + TOGGLE_STICKY_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_STICKY, Messages.NewsBrowserLabelProvider_STICKY, "/icons/obj16/news_pin_light_tiny.gif", "news_pin_light_tiny.gif", Dynamic.TINY_TOGGLE_STICKY_LINK.getId(news), null); //$NON-NLS-1$//$NON-NLS-2$ /* Expand News when clicking on Title */ link = HANDLER_PROTOCOL + EXPAND_NEWS_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ link(builder, link, newsTitle, cssClass, Dynamic.TITLE_LINK.getId(news), color); /* Subtitle */ StringBuilder subtitleContent = new StringBuilder(); fillSubtitle(subtitleContent, news, labels, false); link(builder, link, subtitleContent.toString(), "subtitle", Dynamic.SUBTITLE_LINK.getId(news), "80, 80, 80"); //$NON-NLS-1$ //$NON-NLS-2$ } /* Otherwise treat normally */ else { if (hasLink) link(builder, (fManageLinks && withManagedLinks) ? URIUtils.toManaged(newsLink) : newsLink, newsTitle, cssClass, Dynamic.TITLE_LINK.getId(news), color); else span(builder, newsTitle, cssClass, Dynamic.TITLE_LINK.getId(news), color); } /* Close: NewsItem/Header/Title */ close(builder, "div"); //$NON-NLS-1$ } /* Delete */ if (withInternalLinks) { /* DIV: NewsItem/Header/Delete */ if (fHeadlinesOnly) div(builder, "delete", "display: none;", Dynamic.DELETE.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ else div(builder, "delete", Dynamic.DELETE.getId(news)); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + DELETE_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_DELETE, Messages.NewsBrowserLabelProvider_DELETE, "/icons/elcl16/remove_small.gif", "remove_small.gif", null, null); //$NON-NLS-1$ //$NON-NLS-2$ /* DIV: NewsItem/Header/Delete */ close(builder, "div"); //$NON-NLS-1$ } /* DIV: NewsItem/Header/Subline */ if (fHeadlinesOnly) //Hidden initially in headlines mode div(builder, "subline", "display: none;", Dynamic.SUBLINE.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ else div(builder, "subline", Dynamic.SUBLINE.getId(news)); //$NON-NLS-1$ builder.append("<table class=\"subline\">"); //$NON-NLS-1$ builder.append("<tr class=\"subline\">"); //$NON-NLS-1$ /* Actions */ if (withInternalLinks) { /* Toggle Read */ builder.append("<td class=\"firstactionsubline\">"); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + TOGGLE_READ_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ String text = (news.getState() == INews.State.READ) ? Messages.NewsBrowserLabelProvider_MARK_UNREAD : Messages.NewsBrowserLabelProvider_MARK_READ; imageLink(builder, link, text, text, "/icons/elcl16/mark_read_light.gif", "mark_read_light.gif", Dynamic.TOGGLE_READ_LINK.getId(news), Dynamic.TOGGLE_READ_IMG.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ /* Toggle Sticky */ builder.append("<td class=\"otheractionsubline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + TOGGLE_STICKY_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_STICKY, Messages.NewsBrowserLabelProvider_STICKY, news.isFlagged() ? "/icons/obj16/news_pinned_light.gif" : "/icons/obj16/news_pin_light.gif", news.isFlagged() ? "news_pinned_light.gif" : "news_pin_light.gif", Dynamic.TOGGLE_STICKY_LINK.getId(news), Dynamic.TOGGLE_STICKY_IMG.getId(news)); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ builder.append("</td>"); //$NON-NLS-1$ /* Assign Labels */ builder.append("<td class=\"otheractionsubline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + LABELS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_ASSIGN_LABELS, Messages.NewsBrowserLabelProvider_LABEL, "/icons/elcl16/labels_light.gif", "labels_light.gif", Dynamic.LABELS_MENU_LINK.getId(news), null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ /* Archive News */ builder.append("<td class=\"otheractionsubline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + ARCHIVE_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_ARCHIVE_NEWS, Messages.NewsBrowserLabelProvider_ARCHIVE, "/icons/etool16/archive_light.gif", "archive_light.gif", Dynamic.ARCHIVE_LINK.getId(news), null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ /* Share News Context Menu */ builder.append("<td class=\"otheractionsubline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + SHARE_NEWS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_SHARE_NEWS, Messages.NewsBrowserLabelProvider_SHARE, "/icons/elcl16/share_light.gif", "share_light.gif", Dynamic.SHARE_MENU_LINK.getId(news), null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ /* News Context Menu */ builder.append("<td class=\"otheractionsubline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + NEWS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_MENU, Messages.NewsBrowserLabelProvider_MENU, "/icons/obj16/menu_light.gif", "menu_light.gif", Dynamic.NEWS_MENU_LINK.getId(news), null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"actionsublineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ } /* Date */ builder.append("<td class=\"subline\">"); //$NON-NLS-1$ fillDate(news, builder); builder.append("</td>"); //$NON-NLS-1$ /* Author */ IPerson author = news.getAuthor(); if (author != null) { builder.append("<td class=\"sublineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"subline\">"); //$NON-NLS-1$ fillAuthor(builder, author, true); builder.append("</td>"); //$NON-NLS-1$ } /* Feed Information */ if (showFeedInformation()) { String feedName = getFeedName(news); if (StringUtils.isSet(feedName)) { builder.append("<td class=\"sublineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"subline\">"); //$NON-NLS-1$ builder.append(feedName); builder.append("</td>"); //$NON-NLS-1$ } } /* Comments */ if (StringUtils.isSet(news.getComments()) && news.getComments().trim().length() > 0 && URIUtils.looksLikeLink(news.getComments())) { builder.append("<td class=\"sublineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"subline\">"); //$NON-NLS-1$ String comments = news.getComments(); imageLink(builder, comments, Messages.NewsBrowserLabelProvider_READ_COMMENTS, Messages.NewsBrowserLabelProvider_COMMENTS, "/icons/obj16/comments_light.gif", "comments_light.gif", null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ } boolean hasAttachments = false; List<IAttachment> attachments = news.getAttachments(); for (IAttachment attachment : attachments) { if (attachment.getLink() != null) { hasAttachments = true; break; } } /* Attachments Menu */ if (hasAttachments) { builder.append("<td class=\"sublineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"subline\">"); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + ATTACHMENTS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_ATTACHMENTS, Messages.NewsBrowserLabelProvider_ATTACHMENTS, "/icons/obj16/attachment_light.gif", "attachment_light.gif", Dynamic.ATTACHMENTS_MENU_LINK.getId(news), null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ } /* Labels Separator */ if (labels.isEmpty()) builder.append("<td id=\"").append(Dynamic.LABELS_SEPARATOR.getId(news)).append("\" class=\"sublineseparator\" style=\"display: none;\">"); //$NON-NLS-1$ //$NON-NLS-2$ else builder.append("<td id=\"").append(Dynamic.LABELS_SEPARATOR.getId(news)).append("\" class=\"sublineseparator\">"); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* Labels */ builder.append("<td id=\"").append(Dynamic.LABELS.getId(news)).append("\" class=\"subline\">"); //$NON-NLS-1$ //$NON-NLS-2$ fillLabels(builder, labels); builder.append("</td>"); //$NON-NLS-1$ /* Close: NewsItem/Header/Actions */ builder.append("</tr>"); //$NON-NLS-1$ builder.append("</table>"); //$NON-NLS-1$ close(builder, "div"); //$NON-NLS-1$ /* Close: NewsItem/Header */ close(builder, "div"); //$NON-NLS-1$ /* News Content */ { /* DIV: NewsItem/Content */ StringBuilder extraCSS = new StringBuilder(); if (fHeadlinesOnly) //Hidden initially in headlines mode extraCSS.append("display: none; "); //$NON-NLS-1$ if (index != 0 && fIsNewsListBGColorDefined && index % 2 != 0) extraCSS.append(fNewsListBGColorCSS); if (extraCSS.length() > 0) div(builder, "content", extraCSS.toString(), Dynamic.CONTENT.getId(news)); //$NON-NLS-1$ else div(builder, "content", Dynamic.CONTENT.getId(news)); //$NON-NLS-1$ /* Content is provided and should be displayed */ if (!fHeadlinesOnly) { if (StringUtils.isSet(description) && description != null && !description.equals(news.getTitle())) builder.append(description); /* Content is not provided */ else { /* Inform the user */ builder.append(Messages.NewsBrowserLabelProvider_NO_CONTENT); /* Provide a link to attempt to download the news content and show it */ if (withInternalLinks && hasLink) { builder.append(" "); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + TRANSFORM_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ link(builder, link, Messages.NewsBrowserLabelProvider_ATTEMPT_DOWNLOAD_AND_DISPLAY, null); } } } /* Close: NewsItem/Content */ close(builder, "div"); //$NON-NLS-1$ } /* News Footer */ if (withInternalLinks && fShowFooter) { /* DIV: NewsItem/Footer */ if (fHeadlinesOnly) //Hidden initially in headlines mode div(builder, news.isFlagged() ? "footerSticky" : "footer", "display: none;", Dynamic.FOOTER.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ else div(builder, news.isFlagged() ? "footerSticky" : "footer", Dynamic.FOOTER.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ /* DIV: NewsItem/Footer/Footerline */ div(builder, "footerline"); //$NON-NLS-1$ builder.append("<table class=\"footerline\">"); //$NON-NLS-1$ builder.append("<tr class=\"footerline\">"); //$NON-NLS-1$ /* Collapse News */ if (fHeadlinesOnly) { builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + COLLAPSE_NEWS_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_COLLAPSE, Messages.NewsBrowserLabelProvider_COLLAPSE_NEWS, null, "/icons/obj16/mono_collapse.gif", "mono_collapse.gif", Dynamic.COLLAPSE_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ } /* Mark Sticky */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ String link = HANDLER_PROTOCOL + TOGGLE_STICKY_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_STICKY, Messages.NewsBrowserLabelProvider_STICKY, null, "/icons/obj16/mono_sticky.gif", "mono_sticky.gif", Dynamic.FOOTER_STICKY_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* Apply Label */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + LABELS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_LABEL, Messages.NewsBrowserLabelProvider_LABEL, null, "/icons/obj16/mono_label.gif", "mono_label.gif", Dynamic.FOOTER_LABEL_MENU_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* Archive */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + ARCHIVE_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_ARCHIVE, Messages.NewsBrowserLabelProvider_ARCHIVE_NEWS, null, "/icons/obj16/mono_archive.gif", "mono_archive.gif", Dynamic.FOOTER_ARCHIVE_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* Share Menu */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + SHARE_NEWS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_SHARE, Messages.NewsBrowserLabelProvider_SHARE_NEWS, null, "/icons/obj16/mono_share.gif", "mono_share.gif", Dynamic.FOOTER_SHARE_MENU_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* News Menu */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + NEWS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_MENU, Messages.NewsBrowserLabelProvider_NEWS_MENU, null, "/icons/obj16/mono_menu.gif", "mono_menu.gif", Dynamic.FOOTER_NEWS_MENU_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ /* Related News Menu */ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + RELATED_NEWS_MENU_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_RELATED_NEWS, Messages.NewsBrowserLabelProvider_SEARCH_FOR_RELATED_NEWS, null, "/icons/obj16/mono_search.gif", "mono_search.gif", Dynamic.FIND_RELATED_MENU_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ /* Transform News */ if (hasLink) { builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + TRANSFORM_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, Messages.NewsBrowserLabelProvider_FULL_CONTENT, Messages.NewsBrowserLabelProvider_DISPLAY_FULL_CONTENT, null, "/icons/obj16/mono_transform.gif", "mono_transform.gif", Dynamic.FULL_CONTENT_LINK.getId(news), null, Dynamic.FULL_CONTENT_LINK_TEXT.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ } /* Attachments */ if (attachments.size() != 0) { builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ for (IAttachment attachment : attachments) { if (attachment.getLink() != null) { URI attachmentLink = attachment.getLink(); String name = URIUtils.getFile(attachmentLink, OwlUI.getExtensionForMime(attachment.getType())); if (!StringUtils.isSet(name)) name = attachmentLink.toASCIIString(); String size = OwlUI.getSize(attachment.getLength()); if (size != null) name = NLS.bind(Messages.NewsBrowserLabelProvider_NAME_SIZE, StringUtils.htmlEscape(name), size); else name = StringUtils.htmlEscape(name); builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ link = HANDLER_PROTOCOL + ATTACHMENT_HANDLER_ID + "?" + news.getId(); //$NON-NLS-1$ imageLink(builder, link, name, null, null, "/icons/obj16/mono_attachment.gif", "mono_attachment.gif", Dynamic.ATTACHMENT_LINK.getId(news), null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ } } } /* Source */ ISource source = news.getSource(); if (source != null && source.getLink() != null) { link = source.getLink().toASCIIString(); String name = source.getName(); if (StringUtils.isSet(link)) { builder.append("<td class=\"footerlineseparator\">"); //$NON-NLS-1$ builder.append("|"); //$NON-NLS-1$ builder.append("</td>"); //$NON-NLS-1$ if (StringUtils.isSet(name)) name = StringUtils.htmlEscape(name); else name = StringUtils.htmlEscape(link); builder.append("<td class=\"footerline\">"); //$NON-NLS-1$ imageLink(builder, link, name, null, null, "/icons/obj16/mono_source.gif", "mono_source.gif", null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("</td>"); //$NON-NLS-1$ } } /* Close: NewsItem/Footer/Footerline */ builder.append("</tr>"); //$NON-NLS-1$ builder.append("</table>"); //$NON-NLS-1$ close(builder, "div"); //$NON-NLS-1$ /* Close: NewsItem/Footer */ close(builder, "div"); //$NON-NLS-1$ } /* Even though no footer wanted, need to have a div with clear:both to avoid hanging images from content */ else { div(builder, "clearingFooter"); //$NON-NLS-1$ close(builder, "div"); //$NON-NLS-1$ } } /* Close: NewsItem (as needed) */ if (!onlyInnerContent) { close(builder, "div"); //$NON-NLS-1$ /* Headlines Separator (as needed) */ if (fHeadlinesOnly) { if (isVisible) div(builder, "headlinesSeparator", Dynamic.HEADLINE_SEPARATOR.getId(news)); //$NON-NLS-1$ else div(builder, "headlinesSeparator", "display: none;", Dynamic.HEADLINE_SEPARATOR.getId(news)); //$NON-NLS-1$ //$NON-NLS-2$ close(builder, "div"); //$NON-NLS-1$ } } /* Highlight Support (if search is active) */ return highlightSearchTermsIfNecessary(builder.toString()); } private boolean isVisible(EntityGroup group) { if (fViewer != null) return fViewer.getViewModel().isGroupVisible(group.getId()); return true; } private boolean isVisible(INews news) { if (fViewer != null) return fViewer.getViewModel().isNewsVisible(news); return true; } private int getTotalNewsCount() { if (fViewer != null) return fViewer.getViewModel().getNewsCount(); return 0; } private int getVisibleNewsCount() { if (fViewer != null) return fViewer.getViewModel().getVisibleNewsCount(); return 0; } /** * @param latch the page latch in case more entries are shown than allowed per * page. */ private String getLabel(PageLatch latch) { StringBuilder builder = new StringBuilder(); /* Open: Page Latch */ div(builder, "pageLatch", Dynamic.PAGE_LATCH.getId()); //$NON-NLS-1$ /* Page Latch Link to navigate to next page */ String link = HANDLER_PROTOCOL + NEXT_PAGE_HANDLER_ID; imageLink(builder, link, getLatchName(), null, null, "/icons/obj16/mono_transform.gif", "mono_transform.gif", Dynamic.PAGE_LATCH_LINK.getId(), null, Dynamic.PAGE_LATCH_TEXT.getId()); //$NON-NLS-1$ //$NON-NLS-2$ /* Close: Page Latch */ close(builder, "div"); //$NON-NLS-1$ return builder.toString(); } String getLatchName() { return NLS.bind(Messages.NewsBrowserLabelProvider_DISPLAY_MORE_ARTICLES, getVisibleNewsCount(), getTotalNewsCount()); } void fillSubtitle(StringBuilder subtitleContent, INews news, Set<ILabel> labels, boolean withLinks) { /* Subtitle: Date */ fillDate(news, subtitleContent); /* Subtitle: Author */ IPerson author = news.getAuthor(); if (author != null) { subtitleContent.append(" | "); //$NON-NLS-1$ fillAuthor(subtitleContent, author, withLinks); } /* Subtitle: Feed */ if (showFeedInformation()) { String feedName = getFeedName(news); if (StringUtils.isSet(feedName)) { subtitleContent.append(" | "); //$NON-NLS-1$ subtitleContent.append(feedName); } } /* Subtitle: Labels */ if (!labels.isEmpty()) { subtitleContent.append(" | "); //$NON-NLS-1$ fillLabels(subtitleContent, labels); } } private void fillDate(INews news, StringBuilder builder) { Date newsDate = DateUtils.getRecentDate(news); if (DateUtils.isAfterIncludingToday(newsDate, fTodayInMillies)) builder.append(fTimeFormat.format(newsDate)); else builder.append(fDateFormat.format(newsDate)); } private void fillAuthor(StringBuilder builder, IPerson author, boolean withLinks) { String name = author.getName(); String email = (author.getEmail() != null) ? author.getEmail().toASCIIString() : null; if (email != null && !email.contains("mail:")) //$NON-NLS-1$ email = "mailto:" + email; //$NON-NLS-1$ /* Use name as email if valid */ if (email == null && name != null && name.contains("@") && !name.contains(" ")) //$NON-NLS-1$ //$NON-NLS-2$ email = name; if (withLinks && StringUtils.isSet(name) && email != null) link(builder, email, StringUtils.stripTags(name, false), "author"); //$NON-NLS-1$ else if (StringUtils.isSet(name)) builder.append(StringUtils.stripTags(name, false)); else if (withLinks && email != null) link(builder, email, StringUtils.stripTags(email, false), "author"); //$NON-NLS-1$ else if (email != null) builder.append(StringUtils.stripTags(email, false)); else builder.append(Messages.NewsBrowserLabelProvider_UNKNOWN); } private String getFeedName(INews news) { String feedLinkAsText = news.getFeedLinkAsText(); String feedName = fMapFeedLinkToName.get(feedLinkAsText); if (feedName == null) { IBookMark bm = CoreUtils.getBookMark(news.getFeedReference()); if (bm != null) { feedName = StringUtils.htmlEscape(bm.getName()); fMapFeedLinkToName.put(feedLinkAsText, feedName); } } return feedName; } private void fillLabels(StringBuilder builder, Set<ILabel> labels) { if (!labels.isEmpty()) builder.append(Messages.NewsBrowserLabelProvider_LABELS).append(" "); //$NON-NLS-1$ int c = 0; for (ILabel label : labels) { c++; if (c < labels.size()) span(builder, StringUtils.htmlEscape(label.getName()) + ", ", null, label.getColor()); //$NON-NLS-1$ else span(builder, StringUtils.htmlEscape(label.getName()), null, label.getColor()); } } private void div(StringBuilder builder, String cssClass) { builder.append("<div class=\"").append(cssClass).append("\">\n"); //$NON-NLS-1$ //$NON-NLS-2$ } private void div(StringBuilder builder, String cssClass, String id) { builder.append("<div id=\"").append(id).append("\" class=\"").append(cssClass).append("\">\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } private void div(StringBuilder builder, String cssClass, String extraCSS, String id) { builder.append("<div id=\"").append(id).append("\" class=\"").append(cssClass).append("\" style=\"").append(extraCSS).append("\">\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } private void close(StringBuilder builder, String tag) { builder.append("</").append(tag).append(">\n"); //$NON-NLS-1$ //$NON-NLS-2$ } private void link(StringBuilder builder, String link, String content, String cssClass) { link(builder, link, content, cssClass, null); } private void link(StringBuilder builder, String link, String content, String cssClass, String color) { link(builder, link, content, cssClass, null, color); } private void link(StringBuilder builder, String link, String content, String cssClass, String id, String color) { builder.append("<a href=\"").append(link).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ if (cssClass != null) builder.append(" class=\"").append(cssClass).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ if (color != null) builder.append(" style=\"color: rgb(").append(color).append(");\""); //$NON-NLS-1$ //$NON-NLS-2$ if (id != null) builder.append(" id=\"").append(id).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ builder.append(">").append(content).append("</a>"); //$NON-NLS-1$ //$NON-NLS-2$ } private void imageLink(StringBuilder builder, String link, String tooltip, String alt, String imgPath, String imgName, String linkId, String imageId) { imageLink(builder, link, null, tooltip, alt, imgPath, imgName, linkId, imageId, null); } private void imageLink(StringBuilder builder, String link, String text, String tooltip, String alt, String imgPath, String imgName, String linkId, String imageId, String textId) { builder.append("<a"); //$NON-NLS-1$ if (linkId != null) builder.append(" id=\"").append(linkId).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ if (tooltip != null) builder.append(" title=\"").append(tooltip).append("\" href=\"").append(link).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ else builder.append(" href=\"").append(link).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$ builder.append("<img"); //$NON-NLS-1$ if (imageId != null) builder.append(" id=\"").append(imageId).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ String imageUri; if (fIsIE) imageUri = OwlUI.getImageUri(imgPath, imgName); else imageUri = ApplicationServer.getDefault().toResourceUrl(imgPath); if (alt == null) alt = text; if (alt != null) builder.append(" alt=\"").append(alt).append("\" border=\"0\" src=\"").append(imageUri).append("\" />"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ else builder.append(" border=\"0\" src=\"").append(imageUri).append("\" />"); //$NON-NLS-1$ //$NON-NLS-2$ if (text != null) { if (textId != null) builder.append("<span id=\"").append(textId).append("\" style=\"padding-left:3px;\">").append(text).append("</span>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ else builder.append("<span style=\"padding-left:3px;\">").append(text).append("</span>"); //$NON-NLS-1$ //$NON-NLS-2$ } builder.append("</a>"); //$NON-NLS-1$ } private void span(StringBuilder builder, String content, String cssClass, String color) { span(builder, content, cssClass, null, color); } private void span(StringBuilder builder, String content, String cssClass, String id, String color) { if (cssClass != null) builder.append("<span class=\"").append(cssClass).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ else builder.append("<span"); //$NON-NLS-1$ if (color != null) builder.append(" style=\"color: rgb(").append(color).append(");\""); //$NON-NLS-1$ //$NON-NLS-2$ if (id != null) builder.append(" id=\"").append(id).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ builder.append(">").append(content).append("</span>\n"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Renders the provided list of elements in HTML for reading. * * @param elements the elements to render as HTML. * @param base a URI that should be used as base URI for the HTML document. * @param withManagedLinks if set to <code>false</code>, the output will not * contain any managed links. * @return a HTML document with the elements provided rendered properly for * reading. */ public String render(Object[] elements, URI base, boolean withManagedLinks) { /* Store existing settings to restore later */ boolean stripImagesFromNews = fStripImagesFromNews; boolean stripMediaFromNews = fStripMediaFromNews; boolean showFooter = fShowFooter; boolean headlinesOnly = fHeadlinesOnly; boolean showFeedInformation = fForceShowFeedInformation; fStripImagesFromNews = false; fStripMediaFromNews = false; fShowFooter = false; fHeadlinesOnly = false; fForceShowFeedInformation = true; fForceNoGrouping = true; fForceNoPaging = true; try { return internalRender(elements, base, withManagedLinks); } finally { fStripImagesFromNews = stripImagesFromNews; fStripMediaFromNews = stripMediaFromNews; fShowFooter = showFooter; fHeadlinesOnly = headlinesOnly; fForceShowFeedInformation = showFeedInformation; fForceNoGrouping = false; fForceNoPaging = false; } } private String internalRender(Object[] elements, URI base, boolean withManagedLinks) { /* Start HTML */ StringBuilder html = new StringBuilder(); html.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"); //$NON-NLS-1$ /* Windows only: Mark of the Web */ if (Application.IS_WINDOWS) { html.append(IE_MOTW); html.append("\n"); //$NON-NLS-1$ } /* Head */ html.append("<html>\n <head>\n"); //$NON-NLS-1$ /* Append Base URI if available */ if (base != null) { html.append(" <base href=\""); //$NON-NLS-1$ html.append(base); html.append("\">"); //$NON-NLS-1$ } /* Meta */ html.append("\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"); //$NON-NLS-1$ /* CSS */ try { StringWriter writer = new StringWriter(); writeCSS(writer, elements.length == 1, false); html.append(writer.toString()); } catch (IOException e) { /* Will Never Happen */ } /* Open Body */ html.append(" </head>\n <body id=\"owlbody\">\n"); //$NON-NLS-1$ /* Write News */ for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof INews) html.append(getText(elements[i], false, withManagedLinks, i)); } /* End HTML */ html.append("\n </body>\n</html>"); //$NON-NLS-1$ return html.toString(); } }