Java tutorial
/* * TV-Browser * Copyright (C) 04-2003 Martin Oberhauser (darras@users.sourceforge.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * CVS information: * $RCSfile$ * $Source$ * $Date: 2010-09-07 20:42:48 +0200 (Tue, 07 Sep 2010) $ * $Author: bananeweizen $ * $Revision: 6744 $ */ package util.program; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.regex.Pattern; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import org.apache.commons.lang.StringUtils; import tvbrowser.extras.common.InternalPluginProxyIf; import tvbrowser.extras.common.InternalPluginProxyList; import tvbrowser.extras.favoritesplugin.FavoritesPluginProxy; import tvbrowser.extras.favoritesplugin.core.Favorite; import tvbrowser.extras.favoritesplugin.dlgs.FavoriteTreeModel; import tvbrowser.extras.programinfo.ProgramInfo; import util.settings.PluginPictureSettings; import util.settings.ProgramPanelSettings; import util.ui.Localizer; import util.ui.TVBrowserIcons; import util.ui.UiUtilities; import util.ui.html.ExtendedHTMLDocument; import util.ui.html.HTMLTextHelper; import util.ui.html.HorizontalLine; import devplugin.Date; import devplugin.Marker; import devplugin.Plugin; import devplugin.PluginAccess; import devplugin.Program; import devplugin.ProgramFieldType; import devplugin.ProgramInfoHelper; /** * Creates the String for the ProgramInfoDialog */ public class ProgramTextCreator { /** * The Localizer for this class. */ private static final util.ui.Localizer mLocalizer = util.ui.Localizer.getLocalizerFor(ProgramTextCreator.class); private static String mBodyFontSize; /** The used link protocol for actor links */ public static final String TVBROWSER_URL_PROTOCOL = "tvbrowser://"; /** * * @param prog * The Program to show * @param doc * The HTMLDocument. * @param fieldArr The object array with the field types. * @param tFont The title Font. * @param bFont The body Font. * @param showImage If the image should be shown if it is available. * @param showHelpLinks Show the Help-Links (Quality of Data, ShowView) * @return The HTML String. */ public static String createInfoText(Program prog, ExtendedHTMLDocument doc, Object[] fieldArr, Font tFont, Font bFont, boolean showImage, boolean showHelpLinks) { return createInfoText(prog, doc, fieldArr, tFont, bFont, new ProgramPanelSettings( showImage ? ProgramPanelSettings.SHOW_PICTURES_EVER : ProgramPanelSettings.SHOW_PICTURES_NEVER, -1, -1, false, true, 10), showHelpLinks, 100); } /** * * @param prog * The Program to show * @param doc * The HTMLDocument. * @param fieldArr * The object array with the field types. * @param tFont * The title Font. * @param bFont * The body Font. * @param settings * Settings of the ProgramPanel * @param showHelpLinks * Show the Help-Links (Quality of Data, ShowView) * @param zoom The zoom value for the picture. * @return The HTML String. * @since 2.2.2 */ public static String createInfoText(Program prog, ExtendedHTMLDocument doc, Object[] fieldArr, Font tFont, Font bFont, ProgramPanelSettings settings, boolean showHelpLinks, int zoom) { return createInfoText(prog, doc, fieldArr, tFont, bFont, settings, showHelpLinks, zoom, true); } /** * * @param prog * The Program to show * @param doc * The HTMLDocument. * @param fieldArr * The object array with the field types. * @param tFont * The title Font. * @param bFont * The body Font. * @param settings * Settings of the ProgramPanel * @param showHelpLinks * Show the Help-Links (Quality of Data, ShowView) * @param zoom The zoom value for the picture. * @return The HTML String. * @since 2.6 */ public static String createInfoText(Program prog, ExtendedHTMLDocument doc, Object[] fieldArr, Font tFont, Font bFont, PluginPictureSettings settings, boolean showHelpLinks, int zoom) { return createInfoText(prog, doc, fieldArr, tFont, bFont, new ProgramPanelSettings(settings, false), showHelpLinks, zoom, true); } /** * * @param prog * The Program to show * @param doc * The HTMLDocument. * @param fieldArr * The object array with the field types. * @param tFont * The title Font. * @param bFont * The body Font. * @param settings * Settings of the ProgramPanel * @param showHelpLinks * Show the Help-Links (Quality of Data, ShowView) * @param zoom The zoom value for the picture. * @param showPluginIcons If the plugin icons should be shown. * @return The HTML String. * @since 2.5.3 */ public static String createInfoText(Program prog, ExtendedHTMLDocument doc, Object[] fieldArr, Font tFont, Font bFont, ProgramPanelSettings settings, boolean showHelpLinks, int zoom, boolean showPluginIcons) { return createInfoText(prog, doc, fieldArr, tFont, bFont, settings, showHelpLinks, zoom, showPluginIcons, true); } /** * * @param prog * The Program to show * @param doc * The HTMLDocument. * @param fieldArr * The object array with the field types. * @param tFont * The title Font. * @param bFont * The body Font. * @param settings * Settings of the ProgramPanel * @param showHelpLinks * Show the Help-Links (Quality of Data, ShowView) * @param zoom * The zoom value for the picture. * @param showPluginIcons * If the plugin icons should be shown. * @return The HTML String. * @since 3.0 */ public static String createInfoText(Program prog, ExtendedHTMLDocument doc, Object[] fieldArr, Font tFont, Font bFont, ProgramPanelSettings settings, boolean showHelpLinks, int zoom, boolean showPluginIcons, boolean showPersonLinks) { String debugTables = "0"; //set to "1" for debugging, to "0" for no debugging try { // NOTE: All field types are included until type 25 (REPETITION_ON_TYPE) StringBuilder buffer = new StringBuilder(1024); String titleFont, titleSize, bodyFont; int bodyStyle; int titleStyle; if (tFont == null && bFont != null) { titleFont = bodyFont = bFont.getFamily(); titleSize = mBodyFontSize = String.valueOf(bFont.getSize()); titleStyle = bodyStyle = bFont.getStyle(); } else if (tFont != null && bFont != null) { titleFont = tFont.getFamily(); bodyFont = bFont.getFamily(); titleSize = String.valueOf(tFont.getSize()); mBodyFontSize = String.valueOf(bFont.getSize()); titleStyle = tFont.getStyle(); bodyStyle = bFont.getStyle(); } else { return null; } if (fieldArr == null) { return null; } buffer.append("<html>"); buffer.append("<table width=\"100%\" border=\"" + debugTables + "\" style=\"font-family:"); buffer.append(bodyFont); buffer.append(";").append(getCssStyle(bodyStyle)).append("\"><tr>"); buffer.append("<td width=\"60\">"); buffer.append("<p \"align=center\">"); JLabel channelLogo = new JLabel(prog.getChannel().getIcon()); channelLogo.setToolTipText(prog.getChannel().getName()); buffer.append(doc.createCompTag(channelLogo)); buffer.append( "</p></td><td><table width=\"100%\" border=\"" + debugTables + "\" cellpadding=\"0\"><tr><td>"); buffer.append("<div style=\"color:#ff0000; font-size:"); buffer.append(mBodyFontSize); buffer.append(";\"><b>"); Date currentDate = Date.getCurrentDate(); Date programDate = prog.getDate(); if (programDate.equals(currentDate.addDays(-1))) { buffer.append(Localizer.getLocalization(Localizer.I18N_YESTERDAY)); buffer.append(" "); } else if (programDate.equals(currentDate)) { buffer.append(Localizer.getLocalization(Localizer.I18N_TODAY)); buffer.append(" "); } else if (programDate.equals(currentDate.addDays(1))) { buffer.append(Localizer.getLocalization(Localizer.I18N_TOMORROW)); buffer.append(" "); } buffer.append(prog.getDateString()); buffer.append(" "); buffer.append(prog.getTimeString()); if (prog.getLength() > 0) { buffer.append('-'); buffer.append(prog.getEndTimeString()); } buffer.append(" "); buffer.append(prog.getChannel()); buffer.append("</b></div><div style=\"color:#003366; font-size:"); buffer.append(titleSize); buffer.append("; line-height:2.5em; font-family:"); buffer.append(titleFont).append(";").append(getCssStyle(titleStyle)); buffer.append("\">"); buffer.append(prog.getTitle()); buffer.append("</div>"); String episode = CompoundedProgramFieldType.EPISODE_COMPOSITION.getFormattedValueForProgram(prog); if (episode != null && episode.trim().length() > 0) { buffer.append("<div style=\"color:#808080; font-size:"); buffer.append(mBodyFontSize); buffer.append("\">"); buffer.append(episode); buffer.append("</div>"); } buffer.append("</td><td align=\"right\" valign=\"top\"><table border=\"" + debugTables + "\"><tr><td>"); JButton btn = new JButton(TVBrowserIcons.left(TVBrowserIcons.SIZE_SMALL)); buffer.append(doc.createCompTag(btn)); btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ProgramInfo.getInstance().historyBack(); } }); btn.setEnabled(ProgramInfo.getInstance().canNavigateBack()); btn.setToolTipText(ProgramInfo.getInstance().navigationBackwardText()); buffer.append("</td><td>"); btn = new JButton(TVBrowserIcons.right(TVBrowserIcons.SIZE_SMALL)); buffer.append(doc.createCompTag(btn)); btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ProgramInfo.getInstance().historyForward(); } }); btn.setEnabled(ProgramInfo.getInstance().canNavigateForward()); btn.setToolTipText(ProgramInfo.getInstance().navigationForwardText()); buffer.append("</td></tr></table></td></tr></table></td></tr>"); boolean show = false; if (settings.isShowingPictureForPlugins()) { String[] pluginIds = settings.getPluginIds(); Marker[] markers = prog.getMarkerArr(); if (markers != null && pluginIds != null) { for (Marker marker : markers) { for (String pluginId : pluginIds) { if (marker.getId().compareTo(pluginId) == 0) { show = true; break; } } } } } Color foreground = Color.black;//Settings.propProgramPanelForegroundColor.getColor(); if (settings.isShowingPictureEver() || (settings.isShowingPictureInTimeRange() && !ProgramUtilities.isNotInTimeRange(settings.getPictureTimeRangeStart(), settings.getPictureTimeRangeEnd(), prog)) || show || (settings.isShowingPictureForDuration() && settings.getDuration() <= prog.getLength())) { byte[] image = prog.getBinaryField(ProgramFieldType.PICTURE_TYPE); if (image != null) { String line = "<tr><td></td><td valign=\"top\" style=\"color:rgb(" + foreground.getRed() + "," + foreground.getGreen() + "," + foreground.getBlue() + "); font-size:0\">"; buffer.append(line); try { ImageIcon imageIcon = new ImageIcon(image); if (zoom != 100) { imageIcon = (ImageIcon) UiUtilities.scaleIcon(imageIcon, imageIcon.getIconWidth() * zoom / 100); } StringBuilder value = new StringBuilder(); String textField = prog.getTextField(ProgramFieldType.PICTURE_COPYRIGHT_TYPE); if (textField != null) { value.append(textField); } if (settings.isShowingPictureDescription()) { textField = prog.getTextField(ProgramFieldType.PICTURE_DESCRIPTION_TYPE); if (textField != null) { value.append("<br>").append(textField); } } buffer.append(doc.createCompTag(new JLabel(imageIcon))); buffer.append("<div style=\"font-size:"); buffer.append(mBodyFontSize); buffer.append("\">"); buffer.append(value); buffer.append("</div>"); buffer.append("</td></tr>"); } catch (Exception e) { // Picture was wrong; buffer.delete(buffer.length() - line.length(), buffer.length()); } } } Marker[] pluginArr = prog.getMarkerArr(); if (showPluginIcons && (pluginArr != null) && (pluginArr.length != 0)) { addSeparator(doc, buffer); buffer.append("<tr><td valign=\"top\" style=\"color:#808080; font-size:"); buffer.append(mBodyFontSize); buffer.append("\"><b>"); buffer.append(mLocalizer.msg("markedBy", "Marked by")); buffer.append("</b></td><td valign=\"middle\" style=\"font-size:4\">"); openPara(buffer, "info"); // Workaround: Without the the component are not put in one line. buffer.append(" "); for (int markerCount = pluginArr.length - 1; markerCount >= 0; markerCount--) { Icon[] icons = pluginArr[markerCount].getMarkIcons(prog); if (icons != null) { for (int i = icons.length - 1; i >= 0; i--) { JLabel iconLabel = new JLabel(icons[i]); PluginAccess plugin = Plugin.getPluginManager() .getActivatedPluginForId(pluginArr[markerCount].getId()); if (plugin != null) { iconLabel.setToolTipText(plugin.getInfo().getName()); } else { InternalPluginProxyIf internalPlugin = InternalPluginProxyList.getInstance() .getProxyForId(pluginArr[markerCount].getId()); if (internalPlugin != null) { iconLabel.setToolTipText(internalPlugin.getName()); if (internalPlugin.equals(FavoritesPluginProxy.getInstance())) { // if this is a favorite, add the names of the favorite String favTitles = ""; for (Favorite favorite : FavoriteTreeModel.getInstance() .getFavoritesContainingProgram(prog)) { if (favTitles.length() > 0) { favTitles = favTitles + ", "; } favTitles = favTitles + favorite.getName(); } if (favTitles.length() > 0) { iconLabel.setToolTipText( iconLabel.getToolTipText() + " (" + favTitles + ")"); } } } else { iconLabel.setToolTipText(pluginArr[markerCount].toString()); } } buffer.append(doc.createCompTag(iconLabel)); buffer.append(" "); } } } closePara(buffer); buffer.append("</td></tr>"); } PluginAccess[] plugins = Plugin.getPluginManager().getActivatedPlugins(); ArrayList<JLabel> iconLabels = new ArrayList<JLabel>(); for (PluginAccess plugin : plugins) { Icon[] icons = plugin.getProgramTableIcons(prog); if (icons != null) { for (Icon icon : icons) { JLabel iconLabel = new JLabel(icon); iconLabel.setToolTipText(plugin.getInfo().getName()); iconLabels.add(iconLabel); } } } if (showPluginIcons && iconLabels.size() > 0) { addSeparator(doc, buffer); buffer.append("<tr><td valign=\"middle\" style=\"color:#808080; font-size:"); buffer.append(mBodyFontSize); buffer.append("\"><b>"); buffer.append("Plugin-Icons"); buffer.append("</b></td><td valign=\"top\" style=\"font-size:4\">"); openPara(buffer, "info"); // Workaround: Without the the component are not put in one line. buffer.append(" "); for (JLabel iconLabel : iconLabels) { buffer.append(doc.createCompTag(iconLabel)); buffer.append(" "); } closePara(buffer); buffer.append("</td></tr>"); } addSeparator(doc, buffer); for (Object id : fieldArr) { ProgramFieldType type = null; if (id instanceof String) { if (((String) id).matches("\\d+")) { try { type = ProgramFieldType.getTypeForId(Integer.parseInt((String) id, 10)); } catch (Exception e) { // Empty Catch } } if (type == null) { int length = prog.getLength(); if (length > 0 && ((String) id).trim().length() > 0) { buffer.append("<tr><td valign=\"top\" style=\"color:gray; font-size:"); buffer.append(mBodyFontSize); buffer.append("\"><b>"); buffer.append(mLocalizer.msg("duration", "Program duration/<br>-end")); buffer.append("</b></td><td style=\"color:rgb(" + foreground.getRed() + "," + foreground.getGreen() + "," + foreground.getBlue() + "); font-size:"); buffer.append(mBodyFontSize); buffer.append("\">"); openPara(buffer, "time"); String msg = mLocalizer.msg("minutes", "{0} min", length); buffer.append(msg).append(" ("); buffer.append(mLocalizer.msg("until", "until {0}", prog.getEndTimeString())); int netLength = prog.getIntField(ProgramFieldType.NET_PLAYING_TIME_TYPE); if (netLength != -1) { msg = mLocalizer.msg("netMinuted", "{0} min net", netLength); buffer.append(" - ").append(msg); } buffer.append(')'); closePara(buffer); buffer.append("</td></tr>"); addSeparator(doc, buffer); } } } else if (id instanceof CompoundedProgramFieldType) { CompoundedProgramFieldType value = (CompoundedProgramFieldType) id; String entry = value.getFormattedValueForProgram(prog); if (entry != null) { startInfoSection(buffer, value.getName()); buffer.append(HTMLTextHelper.convertTextToHtml(entry, false)); addSeparator(doc, buffer); } } else { type = (ProgramFieldType) id; if (type == ProgramFieldType.DESCRIPTION_TYPE) { String description = checkDescription(prog.getDescription()); if (description != null && description.length() > 0) { addEntry(doc, buffer, prog, ProgramFieldType.DESCRIPTION_TYPE, true, showHelpLinks, showPersonLinks); } else { addEntry(doc, buffer, prog, ProgramFieldType.SHORT_DESCRIPTION_TYPE, true, showHelpLinks, showPersonLinks); } } else if (type == ProgramFieldType.INFO_TYPE) { int info = prog.getInfo(); if ((info != -1) && (info != 0)) { buffer.append("<tr><td valign=\"top\" style=\"color:gray; font-size:"); buffer.append(mBodyFontSize); buffer.append("\"><b>"); buffer.append(type.getLocalizedName()); buffer.append("</b></td><td valign=\"middle\" style=\"font-size:5\">"); openPara(buffer, "info"); // Workaround: Without the the component are not put in one // line. buffer.append(" "); int[] infoBitArr = ProgramInfoHelper.getInfoBits(); Icon[] infoIconArr = ProgramInfoHelper.getInfoIcons(); String[] infoMsgArr = ProgramInfoHelper.getInfoIconMessages(); for (int i = 0; i < infoBitArr.length; i++) { if (ProgramInfoHelper.bitSet(info, infoBitArr[i])) { JLabel iconLabel; if (infoIconArr[i] != null) { iconLabel = new JLabel(infoIconArr[i]); } else { iconLabel = new JLabel(infoMsgArr[i]); } iconLabel.setToolTipText(infoMsgArr[i]); buffer.append(doc.createCompTag(iconLabel)); buffer.append(" "); } } closePara(buffer); buffer.append("</td></tr>"); addSeparator(doc, buffer); } } else if (type == ProgramFieldType.URL_TYPE) { addEntry(doc, buffer, prog, ProgramFieldType.URL_TYPE, true, showHelpLinks, showPersonLinks); } else if (type == ProgramFieldType.ACTOR_LIST_TYPE) { ArrayList<String> knownNames = new ArrayList<String>(); String[] recognizedActors = ProgramUtilities.getActorNames(prog); if (recognizedActors != null) { knownNames.addAll(Arrays.asList(recognizedActors)); } String actorField = prog.getTextField(type); if (actorField != null) { ArrayList<String>[] lists = ProgramUtilities.splitActors(prog); if (lists == null) { lists = splitActorsSimple(prog); } if (lists != null && lists[0].size() > 0) { startInfoSection(buffer, type.getLocalizedName()); buffer.append("<table border=\"0\" cellpadding=\"0\" style=\"font-family:"); buffer.append(bodyFont); buffer.append(";\">"); for (int i = 0; i < lists[0].size(); i++) { String[] parts = new String[2]; parts[0] = lists[0].get(i); parts[1] = ""; if (i < lists[1].size()) { parts[1] = lists[1].get(i); } int actorIndex = 0; if (showPersonLinks) { if (knownNames.contains(parts[0])) { parts[0] = addPersonLink(parts[0]); } else if (knownNames.contains(parts[1])) { parts[1] = addPersonLink(parts[1]); actorIndex = 1; } } buffer.append("<tr><td valign=\"top\">• </td><td valign=\"top\">"); buffer.append(parts[actorIndex]); buffer.append("</td><td width=\"10\"> </td>"); if (parts[1 - actorIndex].length() > 0) { buffer.append("<td valign=\"top\">"); buffer.append(parts[1 - actorIndex]); buffer.append("</td>"); } else { // if roles are missing add next actor in the same line if (i + 1 < lists[0].size() && lists[1].size() == 0) { i++; buffer.append( "<td valign=\"top\">• </td><td valign=\"top\">"); if (showPersonLinks) { buffer.append(addSearchLink(lists[0].get(i))); } else { buffer.append(lists[0].get(i)); } buffer.append("</td>"); } } buffer.append("</td></tr>"); } buffer.append("</table>"); buffer.append("</td></tr>"); addSeparator(doc, buffer); } else { addEntry(doc, buffer, prog, type, showHelpLinks, showPersonLinks); } } } else { addEntry(doc, buffer, prog, type, showHelpLinks, showPersonLinks); } } } if (showHelpLinks) { buffer.append( "<tr><td colspan=\"2\" valign=\"top\" align=\"center\" style=\"color:#808080; font-size:"); buffer.append(mBodyFontSize).append("\">"); buffer.append("<a href=\""); buffer.append( mLocalizer.msg("dataInfo", "http://wiki.tvbrowser.org/index.php/Qualit%C3%A4t_der_Daten")) .append("\">"); buffer.append(mLocalizer.msg("dataQuality", "Details of the data quality")); buffer.append("</a>"); buffer.append("</td></tr>"); } buffer.append("</table></html>"); return buffer.toString(); } catch (Exception e) { e.printStackTrace(); } return ""; } private static String getCssStyle(final int style) { StringBuilder result = new StringBuilder(); if ((style & Font.BOLD) == Font.BOLD) { result.append("font-weight:bold;"); } if ((style & Font.ITALIC) == Font.ITALIC) { result.append("font-style:italic;"); } return result.toString(); } private static String checkDescription(String desc) { if (desc != null) { desc = desc.trim(); // remove duplicate lines directly after each other StringBuilder buffer = new StringBuilder(); String[] lines = desc.split("\n"); for (int i = 0; i < lines.length; i++) { if (i == 0 || !lines[i].equals(lines[i - 1])) { if (buffer.length() > 0) { buffer.append('\n'); } buffer.append(lines[i]); } } desc = buffer.toString(); int size = 50; if (desc.length() >= size) { // search re-occurings in the description, independent of line breaks int index = desc.indexOf(desc.substring(0, size), size); if (index >= size) { if (desc.indexOf(desc.substring(0, index - 1).trim(), index) == index) { desc = desc.substring(index).trim(); } } } return desc; } return null; } private static String addPersonLink(final String name) { if (name == null || name.isEmpty()) { return mLocalizer.msg("unknown", "(unknown)"); } return addSearchLink(name); } private static ArrayList<String>[] splitActorsSimple(Program prog) { @SuppressWarnings("unchecked") ArrayList<String> list1 = new ArrayList(); @SuppressWarnings("unchecked") ArrayList<String> list2 = new ArrayList(); String actorField = prog.getTextField(ProgramFieldType.ACTOR_LIST_TYPE).trim(); String[] actors; // don't try any parsing if newlines and commas are available // this must be recognized by the more advanced actors parsing if (actorField.contains("\n")) { if (actorField.contains(",")) { return null; } actors = actorField.split("\n"); } else if (actorField.contains(",")) { actors = actorField.split(","); } else if (actorField.contains("\t")) { actors = new String[1]; actors[0] = actorField; } else { return null; } for (String actor : actors) { actor = actor.trim(); if (actor.length() > 0) { String part1 = actor; String part2 = ""; if (actor.contains("\t")) { part1 = StringUtils.substringBefore(actor, "\t").trim(); part2 = StringUtils.substringAfter(actor, "\t").trim(); } else if (actor.contains("(") && actor.contains(")")) { part1 = actor.substring(0, actor.indexOf("(")).trim(); part2 = actor.substring(actor.indexOf("(") + 1, actor.lastIndexOf(")")).trim(); } list1.add(part1); list2.add(part2); } } @SuppressWarnings("unchecked") ArrayList<String>[] result = new ArrayList[2]; result[0] = list1; result[1] = list2; return result; } private static String addSearchLink(String topic, String displayText) { Color foreground = Color.black;//Settings.propProgramPanelForegroundColor.getColor(); String style = " style=\"color:rgb(" + foreground.getRed() + "," + foreground.getGreen() + "," + foreground.getBlue() + "); border-bottom: 1px dashed;\""; StringBuilder buffer = new StringBuilder(32); buffer.append("<a href=\""); buffer.append(TVBROWSER_URL_PROTOCOL); buffer.append(StringUtils.remove(StringUtils.remove(topic, '"'), '\'')); buffer.append("\" "); buffer.append(style); buffer.append('>'); buffer.append(displayText); buffer.append("</a>"); return buffer.toString(); } private static String addSearchLink(String topic) { if (topic == null || topic.isEmpty()) { return ""; } return addSearchLink(topic, topic); } private static void addEntry(ExtendedHTMLDocument doc, StringBuilder buffer, Program prog, ProgramFieldType fieldType, boolean showHelpLinks, boolean showPersonLinks) { addEntry(doc, buffer, prog, fieldType, false, showHelpLinks, showPersonLinks); } private static void addEntry(ExtendedHTMLDocument doc, StringBuilder buffer, Program prog, ProgramFieldType fieldType, boolean createLinks, boolean showHelpLinks, boolean showPersonLinks) { try { String text = null; String name = fieldType.getLocalizedName(); int blank = name.indexOf(' ', 16); if (blank > 0) { name = name.substring(0, blank) + "<br>" + name.substring(blank + 1); } if (fieldType.getFormat() == ProgramFieldType.TEXT_FORMAT) { text = prog.getTextField(fieldType); if (ProgramFieldType.SHORT_DESCRIPTION_TYPE == fieldType) { text = checkDescription(text); } // Lazily add short description, but only if it differs from description if (fieldType == ProgramFieldType.DESCRIPTION_TYPE) { String description = checkDescription(prog.getDescription()); text = description; if (prog.getShortInfo() != null) { StringBuilder shortInfo = new StringBuilder(checkDescription(prog.getShortInfo()).trim()); // delete "..." at the end, but only for duplication check, not for display while (shortInfo.toString().endsWith(".")) { shortInfo.deleteCharAt(shortInfo.length() - 1); } if (!description.trim().startsWith(shortInfo.toString())) { addEntry(doc, buffer, prog, ProgramFieldType.SHORT_DESCRIPTION_TYPE, true, showHelpLinks); } } text = text.replace("\\-", ""); // replace conditional dashes text = removeArtificialLineBreaks(text); text = HTMLTextHelper.convertTextToHtml(text, createLinks); // scan for moderation in beginning of description String[] lines = text.split("<br>"); String[] tags = { "von und mit", "prsentiert von", "mit", "film von", "moderation", "zu gast" }; for (int i = 0; i < 2; i++) { if (lines.length > i && lines[i].length() < 60) { String line = lines[i]; for (String tag : tags) { if (line.toLowerCase().startsWith(tag) || line.toLowerCase().startsWith(tag + ':')) { String personsString = line.substring(tag.length(), line.length()).trim(); if (personsString.startsWith(":")) { personsString = personsString.substring(1).trim(); } if (personsString.endsWith(".")) { personsString = personsString.substring(0, personsString.length() - 1) .trim(); } String[] persons = personsString.split(" und "); boolean doLink = true; for (String person : persons) { if (person.isEmpty() || !Character.isLetter(person.charAt(0)) || Character.isLowerCase(person.charAt(0))) { doLink = false; break; } } if (doLink) { for (String person : persons) { String[] names = person.split(" "); int partCount = names.length; if (partCount >= 2 && partCount < 4) { for (String n : names) { if (!StringUtils.isAlpha(n)) { doLink = false; } } if (doLink) { text = StringUtils.replaceOnce(text, person, addSearchLink(person)); } } } break; } } } } } } } else if (fieldType.getFormat() == ProgramFieldType.TIME_FORMAT) { text = prog.getTimeFieldAsString(fieldType); } else if (fieldType.getFormat() == ProgramFieldType.INT_FORMAT) { if (fieldType == ProgramFieldType.RATING_TYPE) { int value = prog.getIntField(fieldType); if (value > -1) { text = new DecimalFormat("##.#").format((double) prog.getIntField(fieldType) / 10) + "/10"; } } else { text = prog.getIntFieldAsString(fieldType); if (text == null && fieldType == ProgramFieldType.AGE_LIMIT_TYPE) { final String ageRating = prog.getTextField(ProgramFieldType.AGE_RATING_TYPE); if (ageRating != null && !ageRating.isEmpty()) { int age = ProgramUtilities.getAgeLimit(ageRating); if (age >= 0) { text = Integer.toString(age); } } } } } if (fieldType == ProgramFieldType.ORIGIN_TYPE) { String temp = prog.getIntFieldAsString(ProgramFieldType.PRODUCTION_YEAR_TYPE); if (temp != null && temp.trim().length() > 0) { if (text == null || text.trim().length() < 1) { name = ProgramFieldType.PRODUCTION_YEAR_TYPE.getLocalizedName(); text = temp; } else { name += "/<br>" + ProgramFieldType.PRODUCTION_YEAR_TYPE.getLocalizedName(); text += " " + temp; } } temp = prog.getIntFieldAsString(ProgramFieldType.LAST_PRODUCTION_YEAR_TYPE); if (temp != null && temp.trim().length() > 0) { if (text == null || text.trim().length() < 1) { name = ProgramFieldType.LAST_PRODUCTION_YEAR_TYPE.getLocalizedName(); text = temp; } else { text += " - " + temp; } } } if (text == null || text.trim().length() < 1) { if (ProgramFieldType.CUSTOM_TYPE == fieldType) { text = mLocalizer.msg("noCustom", "No custom information "); } else { return; } } startInfoSection(buffer, name); // add person links if (ProgramFieldType.DIRECTOR_TYPE == fieldType || ProgramFieldType.SCRIPT_TYPE == fieldType || ProgramFieldType.CAMERA_TYPE == fieldType || ProgramFieldType.CUTTER_TYPE == fieldType || ProgramFieldType.MUSIC_TYPE == fieldType || ProgramFieldType.MODERATION_TYPE == fieldType || ProgramFieldType.ADDITIONAL_PERSONS_TYPE == fieldType || ProgramFieldType.PRODUCER_TYPE == fieldType) { if (showPersonLinks && text.length() < 200) { // if field is longer, this is probably not a list of names if (text.endsWith(".")) { text = text.substring(0, text.length() - 1); } String[] persons = splitPersons(text); for (int i = 0; i < persons.length; i++) { // remove duplicate entries boolean duplicate = false; if (i < persons.length - 1) { for (int j = i + 1; j < persons.length; j++) { if (persons[i].equalsIgnoreCase(persons[j])) { duplicate = true; break; } } } if (duplicate) { text = text.replaceFirst(Pattern.quote(persons[i]), "").trim(); if (text.startsWith(",")) { text = text.substring(1).trim(); } text = text.replaceAll(",\\s*,", ","); continue; } // a name shall not have more name parts if (persons[i].trim().split(" ").length <= 3) { String link; if (persons[i].contains("(")) { int index = persons[i].indexOf('('); String topic = persons[i].substring(0, index).trim(); link = addSearchLink(topic) + " " + persons[i].substring(index).trim(); } else { link = addSearchLink(persons[i]); } text = text.replace(persons[i], link); } } } buffer.append(text); } else if (ProgramFieldType.DESCRIPTION_TYPE == fieldType) { buffer.append(text); } else { buffer.append(HTMLTextHelper.convertTextToHtml(text, createLinks)); } if ((ProgramFieldType.CUSTOM_TYPE == fieldType) && (showHelpLinks)) { buffer.append(" (<a href=\"").append( mLocalizer.msg("customInfo", "http://enwiki.tvbrowser.org/index.php/CustomInformation")) .append("\">?</a>)"); } if ((ProgramFieldType.AGE_RATING_TYPE == fieldType) && (showHelpLinks)) { addHelpLink(buffer, mLocalizer.msg("ratingInfo", "http://en.wikipedia.org/wiki/Motion_picture_rating_system")); } buffer.append("</td></tr>"); addSeparator(doc, buffer); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static void addHelpLink(final StringBuilder buffer, final String url) { buffer.append(" (<a href=\"").append(url).append("\">?</a>)"); } private static String[] splitPersons(final String textField) { return ProgramUtilities.splitPersons(textField); } /** * remove line breaks from description texts which are formatted as block text * with lines up to around 80 characters * * @param text * @return floating text */ private static String removeArtificialLineBreaks(String text) { String[] lines = text.split("\n"); if (lines.length > 5) { int avg = (text.length() - lines.length + 1) / lines.length; if (avg < 120 && avg > 50) { StringBuilder result = new StringBuilder(); for (String line : lines) { result.append(line); if (line.length() < avg - 10) { result.append('\n'); } else { result.append(' '); } } return result.toString(); } } return text; } private static void startInfoSection(StringBuilder buffer, String section) { Color foreground = Color.black;//Settings.propProgramPanelForegroundColor.getColor(); buffer.append("<tr><td valign=\"top\" style=\"color:#808080; font-size:"); buffer.append(mBodyFontSize); buffer.append("\"><b>"); buffer.append(section); buffer.append("</b></td><td style=\"color:rgb(" + foreground.getRed() + "," + foreground.getGreen() + "," + foreground.getBlue() + "); font-size:"); buffer.append(mBodyFontSize); buffer.append("\">"); } private static void addSeparator(ExtendedHTMLDocument doc, StringBuilder buffer) { buffer.append("<tr><td colspan=\"2\">"); buffer.append("<div style=\"font-size:0;\">").append(doc.createCompTag(new HorizontalLine())) .append("</div></td></tr>"); } private static void openPara(StringBuilder buffer, String style) { buffer.append("<div id=\"").append(style).append("\">"); } private static void closePara(StringBuilder buffer) { buffer.append("</div>\n"); } /** * * @return The default order of the entries. */ public static Object[] getDefaultOrder() { ArrayList<Object> list = new ArrayList<Object>(Arrays.asList(new Object[] { ProgramFieldType.GENRE_TYPE, ProgramFieldType.DESCRIPTION_TYPE, ProgramFieldType.ADDITIONAL_INFORMATION_TYPE, ProgramFieldType.RATING_TYPE, ProgramFieldType.ORIGIN_TYPE, ProgramFieldType.DIRECTOR_TYPE, ProgramFieldType.SCRIPT_TYPE, ProgramFieldType.ACTOR_LIST_TYPE, ProgramFieldType.MODERATION_TYPE, ProgramFieldType.MUSIC_TYPE, ProgramFieldType.PRODUCER_TYPE, ProgramFieldType.CAMERA_TYPE, ProgramFieldType.CUTTER_TYPE, ProgramFieldType.ADDITIONAL_PERSONS_TYPE, ProgramFieldType.URL_TYPE, ProgramFieldType.ORIGINAL_TITLE_TYPE, ProgramFieldType.ORIGINAL_EPISODE_TYPE, ProgramFieldType.PRODUCTION_COMPANY_TYPE, ProgramFieldType.REPETITION_OF_TYPE, ProgramFieldType.REPETITION_ON_TYPE, ProgramFieldType.AGE_LIMIT_TYPE, ProgramFieldType.INFO_TYPE, ProgramFieldType.VPS_TYPE, ProgramFieldType.CUSTOM_TYPE, getDurationTypeString() })); // append missing fields (which may have been added in recent versions) for (Iterator<ProgramFieldType> iterator = ProgramFieldType.getTypeIterator(); iterator.hasNext();) { ProgramFieldType type = iterator.next(); // exclude binary information which need special handling anyway if (type.getFormat() == ProgramFieldType.BINARY_FORMAT) { continue; } if (!list.contains(type)) { list.add(type); } } return list.toArray(); } /** * @return The String for the duration/end of a program. */ public static String getDurationTypeString() { return mLocalizer.msg("duration", "Program duration/<br>-end").replaceAll("<br>", ""); } }