Java tutorial
/* * Zettelkasten - nach Luhmann ** Copyright (C) 2001-2014 by Daniel Ldecke (http://www.danielluedecke.de) * * Homepage: http://zettelkasten.danielluedecke.de * * * 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 3 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, see <http://www.gnu.org/licenses/>. * * * Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU * General Public License, wie von der Free Software Foundation verffentlicht, weitergeben * und/oder modifizieren, entweder gem Version 3 der Lizenz oder (wenn Sie mchten) * jeder spteren Version. * * Die Verffentlichung dieses Programms erfolgt in der Hoffnung, da es Ihnen von Nutzen sein * wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder * der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der * GNU General Public License. * * Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm * erhalten haben. Falls nicht, siehe <http://www.gnu.org/licenses/>. */ package de.danielluedecke.zettelkasten.util; import de.danielluedecke.zettelkasten.database.BibTex; import de.danielluedecke.zettelkasten.util.classes.Comparer; import de.danielluedecke.zettelkasten.database.Daten; import de.danielluedecke.zettelkasten.database.Settings; import de.danielluedecke.zettelkasten.tasks.export.ExportTools; import java.awt.Image; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import org.jdom2.Element; /** * This class is responsible for the creation of a html page of an zettelkasten entry * which is then displayed in the main window's JEditorPane. * * @author danielludecke */ public class HtmlUbbUtil { /** * get the strings for file descriptions from the resource map */ private static final org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application .getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).getContext() .getResourceMap(HtmlUbbUtil.class); private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().startsWith("windows"); private static String[] highlightTermsSearch = null; private static String[] highlightTermsKeywords = null; private static String[] highlightTermsLivesearch = null; public static final int HIGHLIGHT_STYLE_SEARCHRESULTS = 1; public static final int HIGHLIGHT_STYLE_KEYWORDS = 2; public static final int HIGHLIGHT_STYLE_LIVESEARCH = 3; private static boolean highlightWholeWord; private static final int RATING_VALUE_NONE = 1; private static final int RATING_VALUE_HALF = 2; private static final int RATING_VALUE_FULL = 3; /** * This method creates the image-tag for a rating-point * * @param ratingvalue the ratingvalue, i.e. whether the image-tag should contain a full, half or no value-point-image. * use following constants:<br> * <ul> * <li>{@link #RATING_VALUE_FULL RATING_VALUE_FULL}</li> * <li>{@link #RATING_VALUE_FULL RATING_VALUE_HALF}</li> * <li>{@link #RATING_VALUE_FULL RATING_VALUE_NONE}</li> * </ul> * @return the HTML-formatted image-tag with the requested rating-symbol */ private static String getRatingSymbol(int ratingvalue) { // create value for img-name URL imgURL = null; // init return value, i.e. the image-tag StringBuilder imgtag = new StringBuilder("<img border=\"0\" src=\""); // check which image to choose switch (ratingvalue) { // no rating point case RATING_VALUE_NONE: imgURL = org.jdesktop.application.Application .getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).getClass() .getResource("/de/danielluedecke/zettelkasten/resources/icons/bullet_black.png"); break; // half rating point case RATING_VALUE_HALF: imgURL = org.jdesktop.application.Application .getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).getClass() .getResource("/de/danielluedecke/zettelkasten/resources/icons/bullet_yellow.png"); break; // full rating point case RATING_VALUE_FULL: imgURL = org.jdesktop.application.Application .getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).getClass() .getResource("/de/danielluedecke/zettelkasten/resources/icons/bullet_green.png"); break; } // append image-src imgtag.append(imgURL); // and close tag imgtag.append("\">"); // return result return imgtag.toString(); } /** * This method creates and returns a string which contains the CSS-style-definition for * highlighting text / words / keywords / live-search results in a jEditorPane. * * @param settingsObj a reference to the CSettings-class * @return a string which contains the CSS-style-definition for highlighting keywords */ private static String getHighlightCSS(Settings settingsObj) { StringBuilder highlightCss = new StringBuilder(""); highlightCss.append(getHighlightCSS(settingsObj, HIGHLIGHT_STYLE_KEYWORDS)); highlightCss.append(getHighlightCSS(settingsObj, HIGHLIGHT_STYLE_SEARCHRESULTS)); highlightCss.append(getHighlightCSS(settingsObj, HIGHLIGHT_STYLE_LIVESEARCH)); return highlightCss.toString(); } /** * This method creates and returns a string which contains the CSS-style-definition for * highlighting text / words / keywords / live-search results in a jEditorPane. * * @param settingsObj a reference to the CSettings-class * @param style * @return a string which contains the CSS-style-definition for highlighting keywords */ private static String getHighlightCSS(Settings settingsObj, int style) { // prepare antoher string builder for this css-style, because we need // it twice... see author-css below StringBuilder highlightsb = new StringBuilder(""); String css; // select css-style switch (style) { case HIGHLIGHT_STYLE_KEYWORDS: css = "kw"; break; case HIGHLIGHT_STYLE_SEARCHRESULTS: css = "sr"; break; case HIGHLIGHT_STYLE_LIVESEARCH: css = "ls"; break; default: css = "kw"; break; } // prepare the style for highlighting the search terms in // the search results window highlightsb.append(".hs_").append(css).append("{"); // when the user wants to have a background-color, show this now... if (settingsObj.getShowHighlightBackground(style)) { highlightsb.append("background-color:#").append(settingsObj.getHighlightBackgroundColor(style)) .append(";"); } highlightsb.append("color:#"); highlightsb.append(settingsObj.getHighlightSearchStyle(Settings.FONTCOLOR, style)); highlightsb.append(";font-size:1."); highlightsb.append(settingsObj.getHighlightSearchStyle(Settings.FONTSIZE, style)); highlightsb.append("em;"); // get the fontweight-setting String fw = settingsObj.getHighlightSearchStyle(Settings.FONTWEIGHT, style); // apply font-weight-setting only if it's not the default-value, otherwise // bold text would be displayed in normal-fontweight instead. if (!fw.equalsIgnoreCase("normal")) { highlightsb.append("font-weight:"); highlightsb.append(fw); highlightsb.append(";"); } // get the fontstyle-setting String fs = settingsObj.getHighlightSearchStyle(Settings.FONTSTYLE, style); // apply font-style-setting only if it's not the default-value, otherwise // italic text would be displayed in non-italic instead. if (!fs.equalsIgnoreCase("normal")) { highlightsb.append("font-style:"); highlightsb.append(fs); } highlightsb.append("}").append(System.getProperty("line.separator")); return highlightsb.toString(); } /** * This method creates a HTML-layer ({@code div}-tag) which contains the graphical elements * for the rating of an entry. This methods returns a HTML-snippet as string which can be * inserted anywhere inside a {@code body}-element. * * @param dataObj a reference to the {@code CDaten}-class, needed for accessing the methods * that retrieve the rating-values from entries. * @param entrynr the entry-number of the requested entry which rating should be created. * @param sourceframe a reference to the frame from where this function call came. needed for * the html-formatting, since entries are differently formatted in the search window. * @return a HTML-snippet as string which can be inserted anywhere inside a {@code body}-element. */ private static String getEntryHeadline(Daten dataObj, int entrynr, int sourceframe) { // retrieve rating value float ratingvalue = dataObj.getZettelRating(entrynr); // init return value which will contain the html-snippet StringBuilder htmlrating = new StringBuilder(""); // *********************************************** // count total words of entry // *********************************************** // get complete entry-content, i.e. title and content String wordcoutnstring = dataObj.getZettelTitle(entrynr) + " " + dataObj.getCleanZettelContent(entrynr); // split complete content at each word String[] words = wordcoutnstring.toLowerCase().replace("", "ae").replace("", "oe").replace("", "ue") .replace("", "ss").split("\\W"); // init wordcounter int wordcount = 0; // iterate all words of the entry for (String word : words) { // remove all non-letter-chars word = word.replace("([^A-Za-z0-9]+)", ""); // trim spaces word = word.trim(); // if we have a "word" with more than one char, count it as word... if (!word.isEmpty() /* && word.length()>1 */) { wordcount++; } } // *********************************************** // init div and table tag // *********************************************** htmlrating.append(System.getProperty("line.separator")).append("<div class=\"entryrating\">"); htmlrating.append("<table "); if (PlatformUtil.isJava7OnMac() || PlatformUtil.isJava7OnWindows()) htmlrating.append("cellspacing=\"0\" "); htmlrating.append("class=\"tabentryrating\"><tr>").append(System.getProperty("line.separator")); // *********************************************** // init entry heading with entry nr and word count // *********************************************** htmlrating.append("<td colspan=\"2\" class=\"leftcellentryrating\">"); // when the displayed entry differs from the current activated, show this to the user if (entrynr != dataObj.getCurrentZettelPos() && sourceframe != Constants.FRAME_SEARCH) { htmlrating.append("<a class=\"elink\" href=\"#activatedEntry\">"); htmlrating.append(resourceMap.getString("zettelDesc")); htmlrating.append(" ").append(String.valueOf(dataObj.getCurrentZettelPos())) .append(" » "); htmlrating.append(String.valueOf(entrynr)); htmlrating.append(" (").append(String.valueOf(wordcount)).append(" ") .append(resourceMap.getString("activatedZettelWordCount")).append(")"); htmlrating.append("</a>"); } // else show usual entry nr else { htmlrating.append(resourceMap.getString("zettelDesc")); htmlrating.append(" "); htmlrating.append(String.valueOf(entrynr)); htmlrating.append(" (").append(String.valueOf(wordcount)).append(" ") .append(resourceMap.getString("activatedZettelWordCount")).append(")"); } htmlrating.append("</td><td class=\"midcellentryrating\">"); // *********************************************** // now we have to add the timestamp of the entry // *********************************************** htmlrating.append(getEntryTimestamp(dataObj, entrynr)); // *********************************************** // entry rating // *********************************************** htmlrating.append("</td><td class=\"rightcellentryrating\">"); // start hyperlink-tag htmlrating.append("<a class=\"rlink\" href=\"#rateentry").append(String.valueOf(entrynr)).append("\">"); htmlrating.append(resourceMap.getString("ratingText")).append(": "); // count down 5 steps, so we have a maximum of five images int cnt = 5; // loop while (cnt-- > 0) { // add image. therefore, check whether the rating has at least one star if (ratingvalue >= 1.0) { htmlrating.append(getRatingSymbol(RATING_VALUE_FULL)); } // if not, check whether at least a half point is needed else if (ratingvalue >= 0.5) { htmlrating.append(getRatingSymbol(RATING_VALUE_HALF)); } // or, finally, use the image for no rating-points else { htmlrating.append(getRatingSymbol(RATING_VALUE_NONE)); } // decrease rating value by one ratingvalue--; } // close hyperlink htmlrating.append("</a>"); // close tag htmlrating.append("</td></tr>").append(System.getProperty("line.separator")); // check whether entry has manual links String[] manlinks = dataObj.getManualLinksAsString(entrynr); if (manlinks != null && manlinks.length > 0) { // append manual links htmlrating.append("<tr><td class=\"crtitle\" valign=\"top\"><a href=\"#crt\">"); htmlrating.append(resourceMap.getString("crossRefText")) .append(":</a> </td><td class=\"mlink\" colspan=\"3\">"); // create string builder StringBuilder crossrefs = new StringBuilder(""); // iterate string array for (String ml : manlinks) { String title = ""; try { title = dataObj.getZettelTitle(Integer.parseInt(ml)); title = title.replace("\"", "").replace("'", ""); } catch (NumberFormatException ex) { } crossrefs.append("<a href=\"#cr_").append(ml).append("\" title=\"").append(title.trim()) .append("\">").append(ml).append("</a>"); crossrefs.append(" · "); } // append string, but delete last 10 chars, which are " · " htmlrating.append(crossrefs.toString().substring(0, crossrefs.length() - 10)); htmlrating.append("</td></tr>").append(System.getProperty("line.separator")); } htmlrating.append("</table></div>").append(System.getProperty("line.separator")); // return result return htmlrating.toString(); } /** * * @param dataObj * @param entrynr * @return */ private static String getEntryAuthors(Daten dataObj, int entrynr, String content, int sourceframe) { StringBuilder retval = new StringBuilder(""); // *********************************************** // get authors // *********************************************** String[] authors = dataObj.getAuthors(entrynr); // separate authors from content retval.append("<h1>").append(resourceMap.getString("authorsText")).append("</h1>") .append(System.getProperty("line.separator")); // check if we have any values if (authors != null && authors.length > 0) { // copy all authors to linked list, so we can remove those authors that have been added // as footnotes LinkedList<String> remainingAuthors = new LinkedList<String>(); remainingAuthors.addAll(Arrays.asList(authors)); // extract footnotes. LinkedList<String> footnotes = Tools.extractFootnotesFromContent(content); // now we have all footnotes, i.e. the author-index-numbers, in the linked // list. now we can create a reference list if (footnotes.size() > 0) { // iterator for the linked list Iterator<String> i = footnotes.iterator(); while (i.hasNext()) { String au = i.next(); try { int aunr = Integer.parseInt(au); retval.append("<p class=\"reflist\"><b>[<a name=\"fn_").append(au).append("\">").append(au) .append("</a>]</b> "); String aus = dataObj.getAuthor(aunr); // remove author from remaining list remainingAuthors.remove(aus); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_LIVESEARCH); aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_KEYWORDS); } // autoconvert url's to hyperlinks // aus = convertHyperlinks(aus.replace("<", "<").replace(">", ">")); aus = convertHyperlinks(aus); retval.append(aus); retval.append("</p>").append(System.getProperty("line.separator")); } catch (NumberFormatException e) { Constants.zknlogger.log(Level.WARNING, e.getLocalizedMessage()); } } // check whether we have any remaining authors that did not appear in footnotes if (remainingAuthors.size() > 0) { // iterator for the linked list Iterator<String> ri = remainingAuthors.iterator(); while (ri.hasNext()) { String aus = ri.next(); retval.append("<p class=\"reflist\">"); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_LIVESEARCH); aus = highlightSearchTerms(aus, HIGHLIGHT_STYLE_KEYWORDS); } // autoconvert url's to hyperlinks // aus = convertHyperlinks(aus.replace("<", "<").replace(">", ">")); aus = convertHyperlinks(aus); retval.append(aus); retval.append("</p>").append(System.getProperty("line.separator")); } } } else { for (String au : authors) { // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { au = highlightSearchTerms(au, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { au = highlightSearchTerms(au, HIGHLIGHT_STYLE_LIVESEARCH); au = highlightSearchTerms(au, HIGHLIGHT_STYLE_KEYWORDS); } // autoconvert url's to hyperlinks au = convertHyperlinks(au); retval.append("<p class=\"reflist\">").append(au).append("</p>") .append(System.getProperty("line.separator")); } } } else { retval.append("<p class=\"reflist\"><i>").append(resourceMap.getString("NoAuthor")).append("</i></p>"); } retval.append("<p></p>"); return retval.toString(); } /** * * @param dataObj * @param settings * @param entrynr * @return */ private static String getEntryRemarks(Daten dataObj, Settings settings, int entrynr, int sourceframe) { StringBuilder retval = new StringBuilder(""); String remarks = dataObj.getRemarks(entrynr); // if we have remarks, replace all return-ubb-tags into html-tags if (!remarks.isEmpty()) { // now copy the content of the entry to a dummy string. here we convert // the format codes into html-tags. the format codes are simplified tags // for the user to enable simple format editing remarks = replaceUbbToHtml(remarks, settings.getMarkdownActivated(), false, false); // autoconvert url's to hyperlinks remarks = convertHyperlinks(remarks); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { remarks = highlightSearchTerms(remarks, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { remarks = highlightSearchTerms(remarks, HIGHLIGHT_STYLE_LIVESEARCH); remarks = highlightSearchTerms(remarks, HIGHLIGHT_STYLE_KEYWORDS); } // after the conversion is done, append the content to the resulting return string retval.append("<h1>").append(resourceMap.getString("remarksText")).append("</h1>") .append(System.getProperty("line.separator")); retval.append("<div class=\"remarks\">").append(remarks).append("</div><p></p>") .append(System.getProperty("line.separator")); } return retval.toString(); } /** * * @param dataObj * @param entrynr * @return */ private static String getEntryAttachments(Daten dataObj, int entrynr, int sourceframe) { StringBuilder retval = new StringBuilder(""); String[] attachments = dataObj.getAttachmentsAsString(entrynr, false); if ((attachments != null) && (attachments.length > 0)) { // we need a temporary buffer again StringBuilder dummylink = new StringBuilder(""); // iterare all attachments for (String att : attachments) { // if it's not an empty element, surround it with html-list-tags if (!att.isEmpty()) { dummylink.append("<li><a href=\"").append(att).append("\">"); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { att = highlightSearchTerms(att, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { att = highlightSearchTerms(att, HIGHLIGHT_STYLE_LIVESEARCH); att = highlightSearchTerms(att, HIGHLIGHT_STYLE_KEYWORDS); } dummylink.append(att); dummylink.append("</a></li>").append(System.getProperty("line.separator")); } } // if there have been attachments, they must be stored in the stringbuffer now // so, if the string buffer has content, append it to the resulting return string if (dummylink.length() > 0) { // apply a class attribute to the attachments, so we can have certain styles // and formatting for the links as well retval.append("<div class=\"attachments\"><h1>").append(resourceMap.getString("HyperlinksHeader")) .append("</h1>").append(System.getProperty("line.separator")).append("<ul>"); retval.append(dummylink.toString()); retval.append("</ul></div><p></p>").append(System.getProperty("line.separator")); } } return retval.toString(); } /** * * @param dataObj * @param entrynr * @return */ private static String getEntryTimestamp(Daten dataObj, int entrynr) { StringBuilder retval = new StringBuilder(""); String created = dataObj.getTimestampCreated(entrynr); String edited = dataObj.getTimestampEdited(entrynr); // check whether we have a timestamp at all if ((created != null) && (!created.isEmpty())) { // and add the created-timestamp retval.append("<a class=\"tslink\" href=\"#tstampc\">") .append(resourceMap.getString("timestampCreated")).append(" ") .append(Tools.getProperDate(created, true)).append("</a>"); // check whether we have a modified-timestamp // if we have a modified-stamp, add it... if ((edited != null) && (!edited.isEmpty())) { retval.append(" · ").append("<a class=\"tslink\" href=\"#tstampe\">") .append(resourceMap.getString("timestampEdited")).append(" ") .append(Tools.getProperDate(edited, true)).append("</a>"); } // and close the tags of the html-part retval.append(System.getProperty("line.separator")); } return retval.toString(); } /** * This method creates a html page of the parameters passed to this class constructor * It is easier to keep the overview over the layout style when the html page, which is * responsible for the "look'n'feel" of an entry, is being created in a separate class * rather than in the CDaten class * * @param settings a reference to the CSettings-class * @param dataObj a reference to the CDaten-class * @param bibtexObj * @param entrynr the entry-number of the entry that should be converted into HTML * @param segmentKeywords the keywords of the entry, separated at each word, used for highlighting * keywords in the content. * @param sourceframe a reference to the frame from where this function call came. needed for * the html-formatting, since entries are differently formatted in the search window. * @return a string with the html-page-content */ public static String getEntryAsHTML(Settings settings, Daten dataObj, BibTex bibtexObj, int entrynr, String[] segmentKeywords, int sourceframe) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's "entry textfield" StringBuilder retval = new StringBuilder(""); // *********************************************** // initiate html-page, header // *********************************************** retval.append("<html><head>").append(System.getProperty("line.separator")); // NEW! // first of all, prepare the header and style information of the main content retval.append("<style>").append(System.getProperty("line.separator")); // get the common style definition for the basic-tags retval.append( getCommonStyleDefinition(settings, segmentKeywords, dataObj.getKeywords(entrynr), false, false)); // close style definition retval.append("</style>").append(System.getProperty("line.separator")); // close header and open body retval.append("</head><body>").append(System.getProperty("line.separator")); // NEW! // *********************************************** // init headline // *********************************************** if (settings.getShowEntryHeadline()) retval.append(getEntryHeadline(dataObj, entrynr, sourceframe)); // now start with the html content itself retval.append("<div class=\"content\">"); // *********************************************** // get entry's title // *********************************************** String title = dataObj.getZettelTitle(entrynr).replace("<", "<").replace(">", ">"); // if the entry has a title, add it surrounded by <h1>-tags if (!title.isEmpty()) { // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if (Constants.FRAME_SEARCH == sourceframe) { title = highlightSearchTerms(title, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { title = highlightSearchTerms(title, HIGHLIGHT_STYLE_LIVESEARCH); title = highlightSearchTerms(title, HIGHLIGHT_STYLE_KEYWORDS); } retval.append("<h1>"); retval.append(title); retval.append("</h1>").append(System.getProperty("line.separator")); } // *********************************************** // get entry's content // *********************************************** String content = dataObj.getZettelContent(entrynr); // if we have content, show it. if (!content.isEmpty()) { // now copy the content of the entry to a dummy string. here we convert // the format codes into html-tags. the format codes are simplified tags // for the user to enable simple format editing String dummy = convertUbbToHtml(settings, dataObj, bibtexObj, content, sourceframe, false, false); // after the conversion is done, append the content to the resulting return string retval.append(dummy); } else { retval.append("<i>").append(resourceMap.getString("deletedEntry")).append("</i>"); } // close all tags properly retval.append("</div>").append(System.getProperty("line.separator")); // check whether we need an appendix at all... boolean appendixNeeded = (dataObj.hasAttachments(entrynr) | dataObj.hasAuthors(entrynr) | dataObj.hasRemarks(entrynr)); if (appendixNeeded) { // *********************************************** // here we start with additional infos that belong to an // entry's appendix. thus, we have different style options // *********************************************** retval.append("<div class=\"appendixcontent\">").append(System.getProperty("line.separator")); // *********************************************** // get remarks // *********************************************** retval.append(getEntryRemarks(dataObj, settings, entrynr, sourceframe)); // *********************************************** // get authors // *********************************************** retval.append(getEntryAuthors(dataObj, entrynr, retval.toString(), sourceframe)); // *********************************************** // now look for attachments // *********************************************** retval.append(getEntryAttachments(dataObj, entrynr, sourceframe)); // close body and html-page retval.append("</div>").append(System.getProperty("line.separator")); } retval.append("</body><html>").append(System.getProperty("line.separator")); // NEW! return retval.toString(); } /** * This method creates the style-definition for author-values in CSS-format, * so it can be used in HTML-editorpanes for formatting the "page" (i.e., the * html-content) * * @param settingsObj a reference to the CSettings-class. * @return a string containing the CSS-definition of the authors. */ public static String getAuthorStyleDefinition(Settings settingsObj) { // reset the temporary string buffer StringBuilder retval = new StringBuilder(""); // append new style information for the next "html-page" // these author information are set to the second textpanel in the main window retval.append("<style>").append(System.getProperty("line.separator")); // body-tag with main font settings retval.append("body{font-family:"); retval.append(settingsObj.getAuthorFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settingsObj.getAuthorFont(Settings.FONTSIZE)); retval.append("px;color:#"); retval.append(settingsObj.getAuthorFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settingsObj.getAuthorFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settingsObj.getAuthorFont(Settings.FONTWEIGHT)); retval.append(";margin:3px}").append(System.getProperty("line.separator")); retval.append("p{margin:0}").append(System.getProperty("line.separator")); // css for links, usually only footnotes. retval.append("a{color:#003399;text-decoration:none}").append(System.getProperty("line.separator")); // copy css-style to retval... retval.append(getHighlightCSS(settingsObj)); retval.append("</style>"); return retval.toString(); } /** * This method converts url's to html-hyperlinks. * @param dummy the string where url's should be converted to hyperlinks * @return the converted string with link-tags around the url's */ public static String convertHyperlinks(String dummy) { // check whether we already found links if (-1 == dummy.indexOf("<a href=")) { // this group also considered ( and ) as end of hyperlink, but // Wikipedia links e.g. would not be converted correctly. // String groupEndOfURL = "[^ \"\\]\\)\\(\\[\\|\\t\\n\\r<]"; // if no hyperlinks have been found yet, do autoconvert String groupEndOfURL = "[^ \"\\]\\[\\|\\t\\n\\r<]"; dummy = dummy.replaceAll("([\\w]+?://" + groupEndOfURL + "*)", "<a href=\"$1\">$1</a>"); dummy = dummy.replaceAll("([^://])(www\\." + groupEndOfURL + "*)", "$1<a href=\"http://$2\">$2</a>"); dummy = dummy.replaceAll("(mailto:)(" + groupEndOfURL + "*)", "$1<a href=\"mailto:$2\">$2</a>"); } return dummy; } /** * This method highlights searchterms, i.e. it replaces (or: surrounds) all occurences of each string-element of * the global array {@code highlighterms} inside the given string {@code dummy} with HTML-Tags * that assign a style to this HTML-Tags that it looks highlighted. * * @param dummy the string where the searchterms should be highlighted * @param style * @return a "converted" string with highlight-HTML-tags surrounding the searchterms */ public static String highlightSearchTerms(String dummy, int style) { return highlightSearchTerms(dummy, style, false); } /** * This method highlights searchterms, i.e. it replaces (or: surrounds) all occurences of each string-element of * the global array {@code highlighterms} inside the given string {@code dummy} with HTML-Tags * that assign a style to this HTML-Tags that it looks highlighted. * * @param dummy the string where the searchterms should be highlighted * @param style * @return a "converted" string with highlight-HTML-tags surrounding the searchterms */ public static String highlightSearchTermsInUBB(String dummy, int style) { return highlightSearchTerms(dummy, style, true); } /** * This method highlights searchterms, i.e. it replaces (or: surrounds) all occurences of each string-element of * the global array {@code highlighterms} inside the given string {@code dummy} with HTML-Tags * that assign a style to this HTML-Tags that it looks highlighted. * * @param dummy the string where the searchterms should be highlighted * @param cssclass either {@code null} if this method is a usual call, or a style-attribute for * the span-tag. the latter is necessary when calling this method when exporting entries to PDF, * since the PDF-HTML-Parser cannot handle class-attributes, so instead we directly put the * style-information into the HTML-tag. * @param isUBB {@code true} if an UBB-string should be converted, {@code false} when an already * converted HTML-Page should be converted. * @return a "converted" string with highlight-HTML-tags surrounding the searchterms */ private static String highlightSearchTerms(String dummy, int style, boolean isUBB) { String cssclass = "class=\"hs_kw\""; String[] highlightterms = null; switch (style) { case HIGHLIGHT_STYLE_KEYWORDS: cssclass = "class=\"hs_kw\""; highlightterms = highlightTermsKeywords; break; case HIGHLIGHT_STYLE_SEARCHRESULTS: cssclass = "class=\"hs_sr\""; highlightterms = highlightTermsSearch; break; case HIGHLIGHT_STYLE_LIVESEARCH: cssclass = "class=\"hs_ls\""; highlightterms = highlightTermsLivesearch; break; } // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... if ((highlightterms != null) && (highlightterms.length > 0)) { // create a new string-array containing the highlightterms. // the highlightterms might be regular expressions, so we check for this // here. if we find a valid pattern, we assume the searchterm is just a one-string-array, // containing the regular expression pattern. if the pattern-compiling fails, we assume we have // a normal array with search terms. // depending on this, the array "findterms" will either contain the results from the matching // regular expresions, or the usual searchterms String[] findterms; // we assume having a regular expression only when we find certain meta-characters // to check for meta characters, we create an array with those chars and check whether // our searchterm "highlighterms" contains at least one of these chars... // if we found one of the meta-chars that indicate that we might have a regular // expression, we try to compile the pattern given in highlighterms. if (Tools.hasRegExChars(highlightterms[0])) { try { // create a pattern from the first search term. if it fails, go on // to the catch-block, else contiue here. Pattern p = Pattern.compile(highlightterms[0]); // now we know we have a valid regular expression. we now want to // retrieve all matching groups Matcher m = p.matcher(dummy); // add each found string to a linked array-list List<String> founds = new ArrayList<String>(); // iterate all matching groups and check whether these "search terms" have already // been added to the linked list. if not, add it, while (m.find()) { if (!founds.contains(m.group())) { founds.add(m.group()); } } // finally, copy contenr of the array list to the findterms. findterms = founds.toArray(new String[founds.size()]); } catch (PatternSyntaxException e) { // when the pattern could not be compiles, we have a "usual" expression // as search term findterms = highlightterms; } } // if we could not find any meta-character, we assume having a "normal" expression // as search term else { findterms = highlightterms; } // iterate array // and surround all search terms with a html-tag to highlight the search term for (String st : findterms) { // but only if the search term is longer than 1 char... if (st.length() > 1) { // st = st.toLowerCase(); // escape all relevant regex-chars in // the search term, that could appear st = Pattern.quote(st); // check for whole word if (highlightWholeWord) st = "\\b" + st + "\\b"; // now replace the searchterm with itself and surrounding html-tags. use // regex-lookahead to avoid a replacement within existing html-tags if (!isUBB) { dummy = dummy.replaceAll("(?i)" + st + "(?![^<>]*>)", "<span " + cssclass + ">$0</span>"); } else { dummy = dummy.replaceAll("(?<![\\[img\\](.*?)\\[/img\\]])" + st, "<span " + cssclass + ">$0</span>"); } } } } return dummy; } /** * Sets the terms that will be highlighted when preparing the entry for display. in case * no highlighting is requested, use {@code null} as parameter. * @param ht the highlighterms as string-array. These terms will be highlighted in the display. * USe {@code null} when no highlight is requested. * @param style * @param wholeword */ public static void setHighlighTerms(String[] ht, int style, boolean wholeword) { // sort array descending, so we have also highlighted words which // are "inside" other words. // if (ht!=null && ht.length>0) { // Arrays.sort(ht, new BackComparer()); // } highlightWholeWord = wholeword; switch (style) { case HIGHLIGHT_STYLE_KEYWORDS: highlightTermsKeywords = ht; break; case HIGHLIGHT_STYLE_SEARCHRESULTS: highlightTermsSearch = ht; break; case HIGHLIGHT_STYLE_LIVESEARCH: highlightTermsLivesearch = ht; highlightWholeWord = false; break; } } /** * This method converts all ubb-tags of an entry, that are used to indicate formatting, * into html-tags. We use this to set up an html-page with the entries content that is * displayed in a jEditorPane. * * @param settings a reference to the CSettings-class * @param dataObj a reference to the CDaten-class * @param bibtexObj * @param c the content of the entry in "raw" format (i.e. as it is stored in the xml-file) * @param sourceframe * @param isExport {@code true} if this method is called from the CExportDlg-dialog, where we * can create tooltips for literatur-footnotes in HTML-format. {@code false} otherwise. * @param createHTMLFootnotes * @return a converted string with html-tags instead of ubb-tags */ public static String convertUbbToHtml(Settings settings, Daten dataObj, BibTex bibtexObj, String c, int sourceframe, boolean isExport, boolean createHTMLFootnotes) { int pos; // create new string String dummy = replaceUbbToHtml(c, settings.getMarkdownActivated(), (Constants.FRAME_DESKTOP == sourceframe), isExport); // convert footnotes dummy = convertFootnotes(dataObj, bibtexObj, settings, dummy, false); // convert movie-tags // dummy = dummy.replaceAll("\\[mov ([^\\[]*)\\]", "<a href=\"#mov$1\">Film</a>"); // highlight text segemtns dummy = convertUbbHighlightSegments(dummy); dummy = dummy.replaceAll("\\[s ([^\\[]*)\\](.*?)\\[/s\\]", "<span class=\"highlight_$1\">$2</span>"); // autoconvert url's to hyperlinks // we have to do this before(!) converting image-tags, otherwise the source-reference (file://) will // be recognized as URL (that methods searches for xxxx://). dummy = convertHyperlinks(dummy); // convert images, including resizing images dummy = convertImages(dataObj, settings, dummy, isExport); // convert possible table tags to html dummy = convertTablesToHTML(dummy); // convert possible form tags to html dummy = convertForms(settings, dataObj, dummy, Constants.EXP_TYPE_HTML, false, isExport); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... but don't highlight search terms on desktop! // desktop has its own live search function... if (Constants.FRAME_DESKTOP != sourceframe) { if (Constants.FRAME_SEARCH == sourceframe) { dummy = highlightSearchTerms(dummy, HIGHLIGHT_STYLE_SEARCHRESULTS); } else { dummy = highlightSearchTerms(dummy, HIGHLIGHT_STYLE_LIVESEARCH); dummy = highlightSearchTerms(dummy, HIGHLIGHT_STYLE_KEYWORDS); } } // when we exort data to HTML-format, we can create tooltips for the footnotes... if (isExport && createHTMLFootnotes) { // create tooltips for the footnotes. pos = 0; while (pos != -1) { // search for link-tag which has a footnote-ankh pos = dummy.indexOf(Constants.footnoteHtmlTag, pos); // if something was found, go on... if (pos != -1) { // find end of href-attribute, so we can exract the author-number int numpos = dummy.indexOf("\"", pos + Constants.footnoteHtmlTag.length()); if (numpos != -1) { // now extract author-number try { // convert substring to integer int authornr = Integer .parseInt(dummy.substring(pos + Constants.footnoteHtmlTag.length(), numpos)); // retrieve author-value and remove all quote-signs String authorval = dataObj.getAuthor(authornr).replace("\"", "").replace("'", ""); // determine close-bracket of a-tag int closebracket = dummy.indexOf(">", pos + Constants.footnoteHtmlTag.length()); if (closebracket != -1) { // insert title-tag inside of footnote-link dummy = dummy.substring(0, closebracket) + " title=\"" + authorval + "\"" + dummy.substring(closebracket); } } catch (NumberFormatException e) { } } // increae pos-counter to avoid endless while-loops... pos += Constants.footnoteHtmlTag.length(); } } } return dummy; } private static String convertFootnotes(Daten data, BibTex bibtexObj, Settings settings, String dummy, boolean isLatex) { if (isLatex) { dummy = dummy.replaceAll("\\[fn ([^\\[]*)\\]", "(FN $1)"); } else { // save find-position List<Integer> start = new ArrayList<Integer>(); List<Integer> end = new ArrayList<Integer>(); try { // create foot note patterm Pattern p = Pattern.compile("\\[fn ([^\\[]*)\\]"); // create matcher Matcher m = p.matcher(dummy); // check for occurences while (m.find()) { // save grouping-positions start.add(m.start()); end.add(m.end()); } // iterate found positions for (int i = start.size() - 1; i >= 0; i--) { // get footnote String fn = dummy.substring(start.get(i) + Constants.FORMAT_FOOTNOTE_OPEN.length(), end.get(i) - 1); // retrieve author value's bibkey String bibkey = data.getAuthorBibKey(Integer.parseInt(fn)); // check whether we have any bibkey-value if (bibkey != null && !bibkey.isEmpty()) { // get formatted author value String formattedAuthor = bibtexObj.getFormattedAuthor(bibkey); // StringBuilder ref = new StringBuilder(""); // check for valid value. if we have formatted author, use this if (formattedAuthor != null && !formattedAuthor.isEmpty()) { ref.append(Constants.footnoteHtmlTag).append(fn).append("\">"); ref.append(formattedAuthor); ref.append("</a>"); } // else use footnote number else { if (settings.getSupFootnote()) { ref.append("<sup>"); } ref.append("[").append(Constants.footnoteHtmlTag).append(fn).append("\">"); ref.append(fn); ref.append("</a>]"); if (settings.getSupFootnote()) { ref.append("</sup>"); } } // now that we have the bibkey, replace footnote with cite-tag dummy = dummy.substring(0, start.get(i)) + ref.toString() + dummy.substring(end.get(i)); } } } catch (PatternSyntaxException ex) { } catch (NumberFormatException ex) { Constants.zknlogger.log(Level.WARNING, ex.getLocalizedMessage()); Constants.zknlogger.log(Level.WARNING, "Could not convert author ID into author number!"); } catch (IndexOutOfBoundsException ex) { } // footnote: [fn 102] becomes <sup>[102]</sup> (or just [102], if no superscription is set) if (settings.getSupFootnote()) { dummy = dummy.replaceAll("\\[fn ([^\\[]*)\\]", "<sup>[" + Constants.footnoteHtmlTag + "$1\">$1</a>]</sup>"); } else { dummy = dummy.replaceAll("\\[fn ([^\\[]*)\\]", "[" + Constants.footnoteHtmlTag + "$1\">$1</a>]"); } } return dummy; } private static String fixImageTags(String dummy) { // init position counter int pos = 0; int pos2; // we now look for the resize-indicator "|" in each image tag. Even if images should // not be resized, we have to insert this char in order to let the regex-replace-all function // work correctly. Thus, each image-tag without "|" inside will get an additional "|" // just befor the closing tag while (pos != -1) { // check whether img-tag exists pos = dummy.indexOf("[img]", pos); // if yes, go on... if (pos != -1) { // ... and check for closing tag pos2 = dummy.indexOf("[/img]", pos); // if found, go on... if (pos2 != -1) { // ...and check whether image tag has an "|" if (-1 == dummy.substring(pos, pos2).indexOf("|")) { // if not, insert such a resize-indicator char dummy = dummy.substring(0, pos2) + "|" + dummy.substring(pos2); } } // and change pos-counter pos = pos2; } } return dummy; } private static String fixImagePaths(String dummy, String imgpath) { // if we have a windows operating system, we have to add an additonal // separator char, so the link to the image starts with "file:///" instead of only "file://" String sep = ""; if (IS_WINDOWS) { imgpath = File.separatorChar + imgpath; sep = String.valueOf(File.separatorChar); } // init position counter int pos = 0; int pos2; // we now look for the resize-indicator "|" in each image tag. Even if images should // not be resized, we have to insert this char in order to let the regex-replace-all function // work correctly. Thus, each image-tag without "|" inside will get an additional "|" // just befor the closing tag while (pos != -1) { // check whether img-tag exists pos = dummy.indexOf("[img]", pos); // if yes, go on... if (pos != -1) { // ... and check for closing tag pos2 = dummy.indexOf("[/img]", pos); // if found, go on... if (pos2 != -1) { try { String path = dummy.substring(pos + 5, pos2); File imgfile = new File(path.substring(0, path.indexOf("|"))); if (!imgfile.exists()) { // image tag: [img]img/gfx.png[/img] becomes <img src="/img/gfx.png"> // first insert the path to the image folder inside the img-src. dummy = dummy.substring(0, pos) + "[img]file://" + imgpath + dummy.substring(pos + 5); } else { // image tag: [img]img/gfx.png[/img] becomes <img src="/img/gfx.png"> // first insert the path to the image folder inside the img-src. dummy = dummy.substring(0, pos) + "[img]file://" + sep + dummy.substring(pos + 5); } } catch (IndexOutOfBoundsException ex) { } } // and change pos-counter pos = pos2; } } return dummy; } private static String convertImages(Daten dataObj, Settings settings, String dummy, boolean isExport) { // fix image tags, needed due to manual resizing with "|"., // so the regex below works dummy = fixImageTags(dummy); // get individual resize values from image tags List<Integer> resizevalues = Tools.getImageResizeValues(dummy); // here we create a path to our image folder. this is needed for // converting image tags, since the image ae copied to an own local folder, // but the source-information only stores the file name, not the path information. // see CNewEntry.java, method "insertImage" for more details // image tag: [img]img/gfx.png[/img] becomes <img src="/img/gfx.png"> // first insert the path to the image folder inside the img-src. // dummy = dummy.replace("[img]", "[img]file://"+imgpath); dummy = fixImagePaths(dummy, settings.getImagePath(dataObj.getUserImagePath(), true)); // dummy = dummy.replaceAll("\\[img\\](.*?)\\[/img\\]", "<img src=\"$1\">"); dummy = dummy.replaceAll("\\[img\\]([^|]*)(.*?)\\[/img\\]", "<img src=\"$1\">"); // check whether the user likes to resize large images to smaller // thumbnails if (settings.getImageResize() || resizevalues.size() > 0) { // find index that searches for img-tags int pos = 0; int valcnt = 0; // addvalue, indicating where to extract the filename of the image. since the windows-os // has an additional "/", this value is different in windows and other systems... int addvalue = (IS_WINDOWS) ? 18 : 17; // find occurences of mage tags while (pos != -1) { pos = dummy.indexOf("<img src=", pos); // if we found an image, go on if (pos != -1) { // find the end of the src-tag, so we know where to find the filename int end = dummy.indexOf("\"", pos + 10); // check for valid value if (end != -1) { try { int width, height, rw, rh; // create a new file from the imagepath File imageFile = new File(dummy.substring(pos + addvalue, end)); try { // try to read the image Image image = new ImageIcon(ImageIO.read(imageFile)).getImage(); // get the image's size (width/height) width = image.getWidth(null); height = image.getHeight(null); // check whether we have predifined resize values... if (resizevalues.size() > 0) { rw = rh = resizevalues.get(valcnt); valcnt++; } // ...or automatic recaling else { // get the preferred maximum width and height rw = settings.getImageResizeWidth(); rh = settings.getImageResizeHeight(); } // if the image is larger than the preffered thumbnail-size, resize // width and heigh (proportionally) if (width > rw) { float faktor = (float) width / rw; width = (int) (width / faktor); height = (int) (height / faktor); } if (height > rh) { float faktor = (float) height / rh; width = (int) (width / faktor); height = (int) (height / faktor); } // create a new string builder StringBuilder resize = new StringBuilder(""); // here we extract the original img-source and add a // width and height attribute. furthermore, the image is // surrounded by a hyperlink-tag that referrs to the original image if (!isExport) { resize.append("<a href=\""); resize.append(dummy.substring(pos + addvalue, end)); resize.append("\">"); } resize.append(dummy.substring(pos, end + 1)); resize.append(" width=\""); resize.append(String.valueOf(width)); resize.append("\" height=\""); resize.append(String.valueOf(height)); resize.append("\" border=\"0\">"); if (!isExport) resize.append("</a>"); // replace old img-tag with new one // we have to do this between-step because we need to know where // the search has to coninute (pos). String newdummy = dummy.substring(0, pos) + resize.toString(); // set search-position indicator pos = newdummy.length(); dummy = newdummy + dummy.substring(end + 2); } catch (IOException ex) { pos = end + 1; } catch (IndexOutOfBoundsException ex) { pos = end + 1; } } catch (IndexOutOfBoundsException ex) { } } } } } return dummy; } private static String replaceUbbToHtml(String dummy, boolean isMarkdownActivated, boolean isDesktop, boolean isExport) { // replace headlines String head1, head2, head3, head4; String head1md, head2md, head3md, head4md; if (isDesktop) { head1 = "<h3>$1</h3>"; head2 = "<h4>$1</h4>"; head3 = "<h5>$1</h5>"; head4 = "<h6>$1</h6>"; head1md = "$1<h3>$2</h3>"; head2md = "$1<h4>$2</h4>"; head3md = "$1<h5>$2</h5>"; head4md = "$1<h6>$2</h6>"; } else { head1 = "<h2>$1</h2>"; head2 = "<h3>$1</h3>"; head3 = "<h4>$1</h4>"; head4 = "<h5>$1</h5>"; head1md = "$1<h2>$2</h2>"; head2md = "$1<h3>$2</h3>"; head3md = "$1<h4>$2</h4>"; head4md = "$1<h5>$2</h5>"; } // check whether markdown is activated // if yes, replace markdown here if (isMarkdownActivated) { // // quotes // dummy = dummy.replaceAll("(?<=\\[br\\])(\\> )(.*?)\\[br\\]", "[q]$2[/q][br]"); // // after quotes have been replaced, replace < and > signs // if (!isExport) dummy = dummy.replace(">", ">").replace("<", "<"); // // bullets // dummy = dummy.replaceAll("(?<=\\[br\\])(\\d\\. )(.*?)\\[br\\]", "<ol><li>$2</li></ol>"); // dummy = dummy.replace("</ol><ol>", ""); // dummy = dummy.replaceAll("(?<=\\[br\\])(\\* )(.*?)(?!\\*)\\[br\\]", "<ul><li>$2</li></ul>"); // dummy = dummy.replace("</ul><ul>", ""); // // bold and italic formatting in markdown // dummy = dummy.replaceAll("\\*\\*\\*(.*?)\\*\\*\\*", "<b><i>$1</i></b>"); // dummy = dummy.replaceAll("___(.*?)___", "<b><i>$1</i></b>"); // // bold formatting // dummy = dummy.replaceAll("__(.*?)__", "<b>$1</b>"); // dummy = dummy.replaceAll("\\*\\*(.*?)\\*\\*", "<b>$1</b>"); // // italic formatting // dummy = dummy.replaceAll("_(.*?)_", "<i>$1</i>"); // // dummy = dummy.replaceAll("\\*(.*?)\\*", "<i>$1</i>"); // // code blocks formatting // dummy = dummy.replaceAll("\\`(.*?)\\`", "<code>$1</code>"); // // headlines // dummy = dummy.replaceAll("#{4} (.*?)\\[br\\]", head4); // dummy = dummy.replaceAll("#{3} (.*?)\\[br\\]", head3); // dummy = dummy.replaceAll("#{2} (.*?)\\[br\\]", head2); // dummy = dummy.replaceAll("#{1} (.*?)\\[br\\]", head1); // // strike // dummy = dummy.replaceAll("---(.*?)---", "<strike>$1</strike>"); // // images // dummy = dummy.replaceAll("[!]{1}\\[([^\\[]+)\\]\\(([^\\)]+)\\)", "[img]$2[/img]"); dummy = dummy.replace("[br]", "\n"); // quotes dummy = dummy.replaceAll("(^|\\n)(\\> )(.*)", "[q]$3[/q]"); // after quotes have been replaced, replace < and > signs if (!isExport) dummy = dummy.replace(">", ">").replace("<", "<"); // bullets dummy = dummy.replaceAll("(^|\\n)(\\d\\. )(.*)", "<ol><li>$3</li></ol>"); dummy = dummy.replace("</ol><ol>", ""); dummy = dummy.replaceAll("(^|\\n)(\\* )(.*)", "<ul><li>$3</li></ul>"); dummy = dummy.replace("</ul><ul>", ""); // bold and italic formatting in markdown dummy = dummy.replaceAll("\\*\\*\\*(.*?)\\*\\*\\*", "<b><i>$1</i></b>"); dummy = dummy.replaceAll("___(.*?)___", "<b><i>$1</i></b>"); // bold formatting dummy = dummy.replaceAll("__(.*?)__", "<b>$1</b>"); dummy = dummy.replaceAll("\\*\\*(.*?)\\*\\*", "<b>$1</b>"); // italic formatting dummy = dummy.replaceAll("_(.*?)_", "<i>$1</i>"); dummy = dummy.replaceAll("\\*(.*?)\\*", "<i>$1</i>"); // code blocks formatting dummy = dummy.replaceAll("\\`(.*?)\\`", "<code>$1</code>"); // headlines dummy = dummy.replaceAll("(^|\\n)#{4} (.*)", head4md); dummy = dummy.replaceAll("(^|\\n)#{3} (.*)", head3md); dummy = dummy.replaceAll("(^|\\n)#{2} (.*)", head2md); dummy = dummy.replaceAll("(^|\\n)#{1} (.*)", head1md); // strike dummy = dummy.replaceAll("---(.*?)---", "<strike>$1</strike>"); // images dummy = dummy.replaceAll("[!]{1}\\[([^\\[]+)\\]\\(([^\\)]+)\\)", "[img]$2[/img]"); dummy = dummy.replace("\n", "[br]"); } else { // if we don't have markdown, and thus no quotes-syntax with "> ...", // we need to replace non-tag-< and > here if (!isExport) dummy = dummy.replace(">", ">").replace("<", "<"); } // new line dummy = dummy.replace("[br]", "<br>"); // hyperlinks dummy = dummy.replaceAll("\\[([^\\[]+)\\]\\(http([^\\)]+)\\)", "<a href=\"http$2\" title=\"http$2\">$1</a>"); // bold formatting: [f] becomes <b> dummy = dummy.replaceAll("\\[f\\](.*?)\\[/f\\]", "<b>$1</b>"); // italic formatting: [k] becomes <i> dummy = dummy.replaceAll("\\[k\\](.*?)\\[/k\\]", "<i>$1</i>"); // underline formatting: [u] becomes <u> dummy = dummy.replaceAll("\\[u\\](.*?)\\[/u\\]", "<u>$1</u>"); // headline: [h4] becomes <h5> dummy = dummy.replaceAll("\\[h4\\](.*?)\\[/h4\\]", head4); // headline: [h3] becomes <h4> dummy = dummy.replaceAll("\\[h3\\](.*?)\\[/h3\\]", head3); // headline: [h2] becomes <h3> dummy = dummy.replaceAll("\\[h2\\](.*?)\\[/h2\\]", head2); // headline: [h1] becomes <h2> dummy = dummy.replaceAll("\\[h1\\](.*?)\\[/h1\\]", head1); // cite formatting: [q] becomes <q> if (isExport) { dummy = dummy.replaceAll("\\[q\\](.*?)\\[/q\\]", "<blockquote>$1</blockquote>"); // quotation marks dummy = dummy.replaceAll("\\[qm\\](.*?)\\[/qm\\]", "<q>$1</q>"); } else { dummy = dummy.replaceAll("\\[q\\](.*?)\\[/q\\]", "<div class=\"zitat\">$1</div>"); // quotation marks dummy = dummy.replace("[qm]", "“"); dummy = dummy.replace("[/qm]", "”"); } // code blocks formatting: [code] becomes <code> dummy = dummy.replaceAll("\\[code\\](.*?)\\[/code\\]", "<code>$1</code>"); // strike-through formatting: [d] becomes <strike> dummy = dummy.replaceAll("\\[d\\](.*?)\\[/d\\]", "<strike>$1</strike>"); // superscript: [sup] becomes <sup> dummy = dummy.replaceAll("\\[sup\\](.*?)\\[/sup\\]", "<sup>$1</sup>"); // subscript: [sub] becomes <sub> dummy = dummy.replaceAll("\\[sub\\](.*?)\\[/sub\\]", "<sub>$1</sub>"); // font dummy = dummy.replaceAll("\\[font ([^\\[]*)\\](.*?)\\[/font\\]", "<span style=\"font-family:$1\">$2</span>"); // center alignment: [c] becomes <center> dummy = dummy.replaceAll("\\[c\\](.*?)\\[/c\\]", "<div style=\"text-align:center\">$1</div>"); // left alignment dummy = dummy.replaceAll("\\[al\\](.*?)\\[/al\\]", "<div style=\"text-align:left\">$1</div>"); // right alignment dummy = dummy.replaceAll("\\[ar\\](.*?)\\[/ar\\]", "<div style=\"text-align:right\">$1</div>"); // justify alignment dummy = dummy.replaceAll("\\[ab\\](.*?)\\[/ab\\]", "<div style=\"text-align:justify\">$1</div>"); // color formatting: [color #rrggbb] becomes <span style="color:#rrggbb"> ([^\\[]*) dummy = dummy.replaceAll("\\[color ([^\\[]*)\\](.*?)\\[/color\\]", "<span style=\"color:$1\">$2</span>"); // background-color formatting: [h #rrggbb] becomes <span style="background-color:#rrggbb"> dummy = dummy.replaceAll("\\[h ([^\\[]*)\\](.*?)\\[/h\\]", "<span style=\"background-color:$1\">$2</span>"); // margins formatting: [m 0.5] becomes <span style="margin-left:0.5cm;margin-right:0.5cm"> // dummy = dummy.replaceAll("\\[m ([^\\[]*)\\]([^\\[]*)\\[/m\\]", "<div style=\"margin-left:$1cm;margin-right:$1cm\">$2</div>"); dummy = dummy.replaceAll("\\[m ([^\\[]*)\\](.*?)\\[/m\\]", "<div style=\"margin-left:$1cm;margin-right:$1cm\">$2</div>"); // unordered list: [l] becomes <ul> dummy = dummy.replaceAll("\\[l\\](.*?)\\[/l\\]", "<ul>$1</ul>"); // ordered list: [n] becomes <ol> dummy = dummy.replaceAll("\\[n\\](.*?)\\[/n\\]", "<ol>$1</ol>"); // bullet points: [*] becomes <li> dummy = dummy.replaceAll("\\[\\*\\](.*?)\\[/\\*\\]", "<li>$1</li>"); // manual links dummy = dummy.replaceAll("\\[z ([^\\[]*)\\](.*?)\\[/z\\]", "<a class=\"manlink\" href=\"#z_$1\">$2</a>"); // remove all new lines after headlines dummy = dummy.replaceAll("\\</h([^\\<]*)\\>\\<br\\>", "</h$1>"); return dummy; } public static String replaceHtmlToUbb(String dummy) { // new line dummy = dummy.replace("<br>", "[br]"); dummy = dummy.replace("<br/>", "[br]"); dummy = dummy.replace("<br />", "[br]"); // bold formatting: [f] becomes <b> dummy = dummy.replaceAll("\\<b\\>(.*?)\\</b\\>", "[f]$1[/f]"); dummy = dummy.replaceAll("\\<strong\\>(.*?)\\</strong\\>", "[f]$1[/f]"); // italic formatting: [k] becomes <i> dummy = dummy.replaceAll("\\<i\\>(.*?)\\</i\\>", "[k]$1[/k]"); dummy = dummy.replaceAll("\\<em\\>(.*?)\\</em\\>", "[k]$1[/k]"); // underline formatting: [u] becomes <u> dummy = dummy.replaceAll("\\<u\\>(.*?)\\</u\\>", "[u]$1[/u]"); // headlines dummy = dummy.replaceAll("\\<h1\\>(.*?)\\</h1\\>", "[h1]$1[/h1]"); dummy = dummy.replaceAll("\\<h2\\>(.*?)\\</h2\\>", "[h2]$1[/h2]"); dummy = dummy.replaceAll("\\<h3\\>(.*?)\\</h3\\>", "[h3]$1[/h3]"); dummy = dummy.replaceAll("\\<h4\\>(.*?)\\</h4\\>", "[h4]$1[/h4]"); dummy = dummy.replaceAll("\\<h5\\>(.*?)\\</h5\\>", "[h5]$1[/h5]"); // lists dummy = dummy.replaceAll("\\<ul\\>(.*?)\\</ul\\>", "[l]$1[/l]"); dummy = dummy.replaceAll("\\<ol\\>(.*?)\\</ol\\>", "[n]$1[/n]"); dummy = dummy.replaceAll("\\<li\\>(.*?)\\</li\\>", "[*]$1[/*]"); return dummy; } /** * This method converts special chars of highlighted segments keywords into chars which * can be read by a CSS-style-sheet. If, for instance, the user has assigned a text segement * with a keyword that contains umlauts, spaces or other special chars, these chars cannot * be used to declare a CSS-class. In this case, all these chars are replaced by a "_". * * @param content the entry's content * @return the entry's content with all appearing highlight-segment-keywords converted */ private static String convertUbbHighlightSegments(String content) { try { // create a pattern from the first search term. if it fails, go on // to the catch-block, else contiue here. Matcher m = Pattern.compile("\\[s ([^\\[]*)\\]").matcher(content); // find all matches and copy the start/end-positions to our arraylist // we now can easily retrieve the found terms and their positions via this // array, thus navigation with find-next and find-prev-buttons is simple while (m.find()) { for (int cnt = 0; cnt < m.groupCount(); cnt++) { String segword = m.group(cnt); String segpart = segword.substring(3); segpart = segpart.replace(" ", "_").replace(":", "_").replace("/", "_").replace("", "ss") .replace("", "ae").replace("", "oe").replace("", "ue").replace("", "Ae") .replace("", "Oe").replace("", "Ue").replace("\\", "_"); content = content.replace(segword, "[s " + segpart); } } } catch (PatternSyntaxException e) { // and leave method return content; } catch (IndexOutOfBoundsException e) { // and leave method return content; } return content; } /** * Since tables cannot be converted using regular expressions (in the * {@link #convertUbbToHtml(zettelkasten.CSettings, java.lang.String) convertUbbToHtml()}-method), * we do this in an extra method. This, this method converts table-tags into HTML-tables. * * @param dummy the entry's content * @return the entry's content, with table-tags converted to HTML */ private static String convertTablesToHTML(String dummy) { // convert tables. we don't do this with regular expressions // first, init the index-variable int pos = 0; int end; // go and find all table-tages while (pos != -1) { // find occurence of opening-tag pos = dummy.indexOf("[table]", pos); // when open-tag was found, go on and find end of table-tag if (pos != -1) { // find closing-tag end = dummy.indexOf("[/table]", pos); // if closing-tag also found, convert content to table if (end != -1) { StringBuilder tabelle = new StringBuilder(); // get table-content String tablecontent = dummy.substring(pos + 7, end); // get table rows String[] tablerows = tablecontent.split(Pattern.quote("<br>")); // init rowcounter int rowcnt = 0; // iterate all table rows for (String row : tablerows) { // remove leading and trailing spaces and tabs // row = row.trim(); // if the row is not empty, go on if (!row.isEmpty()) { // check whether we have a caption if (row.startsWith(Constants.FORMAT_TABLECAPTION_OPEN)) { // replace tags with caption row = row.replace(Constants.FORMAT_TABLECAPTION_OPEN, "<caption>"); row = row.replace(Constants.FORMAT_TABLECAPTION_CLOSE, "</caption>"); // close row--tags tabelle.append(row).append(System.getProperty("line.separator")); } else { // check whether row is table header or a simple data-row. therefore, // look for occurences of "|", which is a cell-separator, or for "^", // whih is the separator for the tableheader boolean isheader = row.contains("^"); // use approprate split-char: | for cells, ^ for header-rows String[] tablecells = row.split((isheader) ? "\\^" : "\\|"); // check whether we have header line if (isheader) { // append opening tag for tablerow tabelle.append("<tr class=\"rowhead\">"); } else { String rowclass = ((rowcnt % 2 == 0) ? "rowodd" : "roweven"); rowcnt++; tabelle.append("<tr class=\"").append(rowclass).append("\">"); } // init columncounter boolean firstcol = true; // iterate each table-data-cell for (String cell : tablecells) { // check whether we have first column or other column // so we can style the appearance of first column separately String colclass = (firstcol) ? "class=\"tfirstcol\"" : "class=\"tothercol\""; firstcol = false; // append td/th-tags with table-data tabelle.append((isheader) ? ("<th " + colclass + ">") : ("<td " + colclass + "valign=\"top\">")); tabelle.append(cell.trim()); tabelle.append((isheader) ? "</th>" : "</td>"); } // close row--tags tabelle.append("</tr>").append(System.getProperty("line.separator")); } } } // dummy = dummy.substring(0, pos)+"<table border=\"1\">"+tabelle.toString().replace("\\\\", "<br>")+"</table>"+dummy.substring(end+8); String tableString = (PlatformUtil.isJava7OnMac() || PlatformUtil.isJava7OnWindows()) ? "<table cellspacing=\"0\">" : "<table>"; dummy = dummy.substring(0, pos) + tableString + tabelle.toString().replace("\\\\", "<br>") + "</table>" + dummy.substring(end + 8); pos = pos + tabelle.toString().length(); } // if no valid end-tag was found, try to find possible // next table tage else { pos += 7; } } } return dummy; } /** * * @param settings * @param dataObj * @param dummy * @param format * @param createFormTag * @param isExport * @return */ private static String convertForms(Settings settings, Daten dataObj, String dummy, int format, boolean createFormTag, boolean isExport) { // TODO weitere formate einfgen, bspw. text? // convert forms. we don't do this with regular expressions // first, init the index-variable int pos = 0; int end; // go and find all form-tages while (pos != -1) { // find occurence of opening-tag pos = dummy.indexOf(Constants.FORMAT_FORM_TAG, pos); // when open-tag was found, go on and find end of table-tag if (pos != -1) { // find closing-tag end = dummy.indexOf("]", pos); // if closing-tag also found, convert content to table if (end != -1) { // check whether the user wants to create a form tag. if so, no graphic is inserted // into the source-code, but for instance a LaTex-macro for creating forms, or // plain text in text files. if (createFormTag) { // extract form information from tag ExtractFormInformation extractedforms = new ExtractFormInformation( dummy.substring(pos, end)); // create replace string String replace = ""; // now convert forms to the correct export-format switch (format) { case Constants.EXP_TYPE_TEX: replace = convertFormsToTex(extractedforms.getDescription(), extractedforms.getDistinctions(), extractedforms.getUnmarkedSpace(), extractedforms.hasReentry()); break; case Constants.EXP_TYPE_HTML: replace = convertFormsToHtml(extractedforms.getDescription(), extractedforms.getDistinctions(), extractedforms.getUnmarkedSpace(), extractedforms.hasReentry()); break; } // and replace form-tag with converted string dummy = dummy.substring(0, pos) + replace + dummy.substring(end + 1); } // here we have no creation of form-tag, so we will insert an image instead. the // form-tags will be replaced by the related form-image. else { // here we create a path to our form-image folder. this is needed for // converting form-image tags, since the image ae copied to an own local folder, // but the source-information only stores the file name, not the path information. String imgpath = settings.getFormImagePath(dataObj.getUserImagePath(), true); // create replace-string StringBuilder replace = new StringBuilder(""); // now convert forms to the correct export-format switch (format) { case Constants.EXP_TYPE_TEX: replace.append("\\includegraphics[scale=0.35]{"); replace.append(imgpath); replace.append(FileOperationsUtil .convertFormtagToImagepath(dummy.substring(pos, end + 1), true, true)); replace.append("}"); break; case Constants.EXP_TYPE_HTML: case Constants.EXP_TYPE_RTF: case Constants.EXP_TYPE_DOCX: case Constants.EXP_TYPE_ODT: // if we have a windows operating system, we have to add an additonal // separator char, so the link to the image starts with "file:///" instead of only "file://" if (IS_WINDOWS) { imgpath = File.separatorChar + imgpath; } // now create html-snippet replace.append("<img "); // when we export the form-images, we use the large version of images, // but we rescale them. the higher resolution means better printing results. if (isExport) { // create a new file from the imagepath File imageFile = new File(imgpath + FileOperationsUtil .convertFormtagToImagepath(dummy.substring(pos, end + 1), true, isExport)); try { // try to read the image Image image = new ImageIcon(ImageIO.read(imageFile)).getImage(); // get the image's size (width/height) int width = image.getWidth(null); int height = image.getHeight(null); // and resize image by 50% replace.append("width=\"").append(String.valueOf(width / 2)) .append("\" height=\"").append(String.valueOf(height / 2)) .append("\" "); } catch (IOException ex) { } } replace.append("src=\""); if (format == Constants.EXP_TYPE_HTML) { replace.append("file://"); } replace.append(imgpath); replace.append(FileOperationsUtil .convertFormtagToImagepath(dummy.substring(pos, end + 1), true, isExport)); replace.append("\">"); break; } // and replace form-tag with converted string dummy = dummy.substring(0, pos) + replace.toString() + dummy.substring(end + 1); } } pos += 3; } } return dummy; } /** * * @param desc * @param distinctions * @param reentry * @return */ private static String convertFormsToTex(String desc, String[] distinctions, String unmarkedSpace, boolean reentry) { StringBuilder sb = new StringBuilder(""); // check for valid parameter if (distinctions != null && distinctions.length > 0) { // create distance from form to text sb.append("\\FormAbstand{"); // get description if (desc != null && !desc.isEmpty()) { sb.append(desc).append(" ="); } // check whether we have a reentry if (reentry) { // open re entry tag sb.append("\\ReEntry{"); } // count distinctions for (int cnt = 0; cnt < distinctions.length - 1; cnt++) { // and add crosses sb.append("\\cross{"); } // iterate distinctions for (String d : distinctions) { // add each distinction sb.append(d).append("}"); } // append unmarked space if (unmarkedSpace != null && !unmarkedSpace.isEmpty()) { sb.append(unmarkedSpace); } // close reentry, if necessary if (reentry) { sb.append("}"); } } return sb.toString(); } /** * * @param desc * @param distinctions * @param reentry * @return */ private static String convertFormsToHtml(String desc, String[] distinctions, String unmarkedSpace, boolean reentry) { // create string builder StringBuilder sb = new StringBuilder(""); // check whether we have a description if (desc != null && !desc.isEmpty()) { // if yes, append it sb.append(desc).append(" = "); } // append first distincion sb.append(distinctions[0]).append(" | "); // append second distincion sb.append(distinctions[1]); // check whether we have two marks (=3 distinctions) if (3 == distinctions.length) { // and if so, append third dist. sb.append(" | ").append(distinctions[2]); } // check whether we have an unmarked space if (unmarkedSpace != null && !unmarkedSpace.isEmpty()) { sb.append(" || ").append(unmarkedSpace); } return sb.toString(); } /** * Since tables cannot be converted using regular expressions (in the * {@link #convertUbbToHtml(zettelkasten.CSettings, java.lang.String) convertUbbToHtml()}-method), * we do this in an extra method. This, this method converts table-tags into HTML-tables. * * @param dummy the entry's content * @return the entry's content, with table-tags converted to HTML */ private static String convertTablesToTex(String dummy, Settings settingsObj) { // convert tables. we don't do this with regular expressions // first, init the index-variable int pos = 0; int end; // if we have statistical table style, don't use vertical column lines / grid String grid = (settingsObj.getLatexExportStatisticTableStyle()) ? "" : "|"; // if we have statistical table style, center table String centertable = (settingsObj.getLatexExportStatisticTableStyle()) ? "\\centering" + System.getProperty("line.separator") : ""; // if we have statistical table style, don't use vertical column lines / grid String tablestart = (settingsObj.getLatexExportStatisticTableStyle()) ? "\\begin{tabular}" : "\\begin{tabularx}{\\textwidth}"; // if we have statistical table style, don't use vertical column lines / grid String tableend = (settingsObj.getLatexExportStatisticTableStyle()) ? "\\end{tabular}" : "\\end{tabularx}"; // caption string String caption = ""; // go and find all table-tages while (pos != -1) { // find occurence of opening-tag pos = dummy.indexOf("[table]", pos); // when open-tag was found, go on and find end of table-tag if (pos != -1) { // find closing-tag end = dummy.indexOf("[/table]", pos); // if closing-tag also found, convert content to table if (end != -1) { StringBuilder tabelle = new StringBuilder(); // init header-row-index int headerrow = 0; // get table-content String tablecontent = dummy.substring(pos + 7, end); // get table rows String[] tablerows = tablecontent.split(System.getProperty("line.separator")); // check for valid values if (tablerows != null && tablerows.length > 0) { // check whether we have a caption if (tablerows[headerrow].startsWith(Constants.FORMAT_TABLECAPTION_OPEN)) { // replace tags with caption tablerows[headerrow] = tablerows[headerrow].replace(Constants.FORMAT_TABLECAPTION_OPEN, "\\caption{"); tablerows[headerrow] = tablerows[headerrow].replace(Constants.FORMAT_TABLECAPTION_CLOSE, "}"); // copy row data caption = tablerows[headerrow]; caption = caption + System.getProperty("line.separator"); // increase header row counter if (tablerows.length > 1) { headerrow = 1; } } // check whether row is table header or a simple data-row. therefore, // look for occurences of "|", which is a cell-separator, or for "^", // whih is the separator for the tableheader boolean isheader = tablerows[headerrow].contains("^"); // use approprate split-char: | for cells, ^ for header-rows String[] tablecells = tablerows[headerrow].split((isheader) ? "\\^" : "\\|"); // if we have a table header, make each cell text bold, if we have // not statistical table style if (isheader && !settingsObj.getLatexExportStatisticTableStyle()) { // create string builder StringBuilder tablecell = new StringBuilder(""); for (String tablecell1 : tablecells) { // enclose text in bold format tablecell.append("\\textbf{").append(tablecell1).append("}^"); } // delete last ^ if (tablecell.length() > 1) { tablecell.setLength(tablecell.length() - 1); } // set back result to table rows array tablerows[headerrow] = tablecell.toString(); } // now check how many columns we have... for (int col = 0; col < tablecells.length; col++) { // append a latex-column if (settingsObj.getLatexExportStatisticTableStyle()) { // align cell content right, if we have // a statistic like table style tabelle.append("r"); } // else, if we have "usual" table style, go on here... else { // only for first columns (labels), choose left alignment // tabelle.append((0==col)?"l":"c"); // new! X stands for variable column widht tabelle.append((0 == col) ? "l" : "X"); } } // close latex-column-count tabelle.append(grid).append("}").append(System.getProperty("line.separator")); // add horozontal line tabelle.append("\\hline").append(System.getProperty("line.separator")); // create table row counter. this is needed for alternate coloring of rows boolean colorrow = false; // count rows... int rowscounted = 0; // iterate all table rows for (String row : tablerows) { // remove leading and trailing spaces and tabs // row = row.trim(); // if the row is not empty, go on if (!row.isEmpty() && !row.startsWith("\\caption{")) { // replace new lines row = row.replaceAll(Pattern.quote("\\\\"), System.getProperty("line.separator")); // check whether row is table header or a simple data-row. therefore, // look for occurences of "|", which is a cell-separator, or for "^", // whih is the separator for the tableheader isheader = row.contains("^"); // use approprate split-char: | for cells, ^ for header-rows row = row.replaceAll((isheader) ? "\\^" : "\\|", " \\& "); // only colorize table cells if we have non-statistical style if (!settingsObj.getLatexExportStatisticTableStyle()) { // check whether we have a header-row if (isheader) { // apply dark gray cell color tabelle.append("\\rowcolor{DarkGray}") .append(System.getProperty("line.separator")); } else { // check whether we have odd row if (colorrow) { // apply light gray cell color tabelle.append("\\rowcolor{LightGray}") .append(System.getProperty("line.separator")); colorrow = false; } else { // apply white cell color tabelle.append("\\rowcolor{white}") .append(System.getProperty("line.separator")); colorrow = true; } } } // close row--tags tabelle.append(row).append(" \\\\ ").append(System.getProperty("line.separator")); // check whether we have first row if (0 == rowscounted) { // increase counter, only needed to find first row rowscounted++; // now check whether we have statistical table style // if so, add two lines if (settingsObj.getLatexExportStatisticTableStyle()) { tabelle.append("\\hline").append("\\hline") .append(System.getProperty("line.separator")); } } } } // create final tex-table-tempplate dummy = dummy.substring(0, pos) + "\\begin{table}[htp]" + System.getProperty("line.separator") + centertable + caption + tablestart + "{" + grid + tabelle.toString() + "\\hline" + System.getProperty("line.separator") + tableend + System.getProperty("line.separator") + "\\end{table}" + dummy.substring(end + 8); pos = pos + tabelle.toString().length(); } } // if no valid end-tag was found, try to find possible // next table tage else { pos += 7; } } } return dummy; } /** * This method converts all ubb-tags of an entry, that are used to indicate formatting, * into html-tags. We use this to set up an html-page with the entries content that is * displayed in a jEditorPane. * * @param settings * @param dataObj * @param bibtexObj * @param c the content of the entry in "raw" format (i.e. as it is stored in the xml-file) * @param useFootnoteRef * @param createFormTag * @param isDesktop * @param removeNonStandardTags * @return a converted string with html-tags instead of ubb-tags */ public static String convertUbbToTex(Settings settings, Daten dataObj, BibTex bibtexObj, String c, boolean useFootnoteRef, boolean createFormTag, boolean isDesktop, boolean removeNonStandardTags) { // here we create a path to our image folder. this is needed for // converting image tags, since the image ae copied to an own local folder, // but the source-information only stores the file name, not the path information. // see CNewEntry.java, method "insertImage" for more details String imgpath = settings.getImagePath(dataObj.getUserImagePath(), true); // if we have a windows operating system, we have to add an additonal // separator char, so the link to the image starts with "file:///" instead of only "file://" // if (IS_WINDOWS) imgpath = File.separatorChar+imgpath; String dummy = (settings.getMarkdownActivated() ? Tools.convertMarkDown2UBB(c) : c); // new line dummy = dummy.replace("[br]", System.getProperty("line.separator")); // italic formatting: [k] becomes <i> dummy = dummy.replaceAll("\\[k\\](.*?)\\[/k\\]", Matcher.quoteReplacement("\\emph{") + "$1" + "}"); // bold formatting: [f] becomes <b> dummy = dummy.replaceAll("\\[f\\](.*?)\\[/f\\]", Matcher.quoteReplacement("\\textbf{") + "$1" + "}"); // underline formatting: [u] becomes <u> dummy = dummy.replaceAll("\\[u\\](.*?)\\[/u\\]", Matcher.quoteReplacement("\\underline{") + "$1" + "}"); if (isDesktop) { // headline: [h1] becomes <h2> dummy = dummy.replaceAll("\\[h1\\](.*?)\\[/h1\\]", Matcher.quoteReplacement("\\paragraph{") + "$1" + "}"); // headline: [h2] becomes <h3> dummy = dummy.replaceAll("\\[h2\\](.*?)\\[/h2\\]", Matcher.quoteReplacement("\\subparagraph{") + "$1" + "}"); } else { // headline: [h1] becomes <h2> dummy = dummy.replaceAll("\\[h1\\](.*?)\\[/h1\\]", Matcher.quoteReplacement("\\subsection{") + "$1" + "}"); // headline: [h2] becomes <h3> dummy = dummy.replaceAll("\\[h2\\](.*?)\\[/h2\\]", Matcher.quoteReplacement("\\subsubsection{") + "$1" + "}"); } // cite formatting: [q] becomes <q> dummy = dummy.replaceAll("\\[q\\](.*?)\\[/q\\]", Matcher.quoteReplacement("\\begin{quotation}") + "$1" + Matcher.quoteReplacement("\\end{quotation}")); // strike-through formatting: [d] becomes <strike> dummy = dummy.replaceAll("\\[d\\](.*?)\\[/d\\]", Matcher.quoteReplacement("\\sout{") + "$1" + "}"); // superscript: [sup] becomes <sup> dummy = dummy.replaceAll("\\[sup\\](.*?)\\[/sup\\]", Matcher.quoteReplacement("\\textsuperscript{") + "$1" + "}"); // subscript: [sub] becomes <sub> dummy = dummy.replaceAll("\\[sub\\](.*?)\\[/sub\\]", Matcher.quoteReplacement("\\textsubscript{") + "$1" + "}"); // center alignment: [c] becomes <center> dummy = dummy.replaceAll("\\[c\\](.*?)\\[/c\\]", Matcher.quoteReplacement("\\begin{center}") + "$1" + Matcher.quoteReplacement("\\end{center}")); // left alignment dummy = dummy.replaceAll("\\[al\\](.*?)\\[/al\\]", Matcher.quoteReplacement("\\begin{flushleft}") + "$1" + Matcher.quoteReplacement("\\end{flushleft}")); // right alignment dummy = dummy.replaceAll("\\[ar\\](.*?)\\[/ar\\]", Matcher.quoteReplacement("\\begin{flushright}") + "$1" + Matcher.quoteReplacement("\\end{flushright}")); // justify alignment dummy = dummy.replaceAll("\\[ab\\](.*?)\\[/ab\\]", "$1"); // color formatting: [color #rrggbb] becomes <span style="color:#rrggbb"> ([^\\[]*) if (!removeNonStandardTags) { dummy = dummy.replaceAll("\\[color ([^\\[]*)\\](.*?)\\[/color\\]", Matcher.quoteReplacement("\\textcolor{[rgb]{$1}") + "$2" + "}"); } // in case the user does not want extra packages, use emph instead of color-tags else { dummy = dummy.replaceAll("\\[color ([^\\[]*)\\](.*?)\\[/color\\]", Matcher.quoteReplacement("\\emph{") + "$2" + "}"); } dummy = dummy.replaceAll("\\[font ([^\\[]*)\\](.*?)\\[/font\\]", "{\\fontfamily{$1}\\selectfont\n$2}"); // background-color formatting: [h #rrggbb] becomes <span style="background-color:#rrggbb"> dummy = dummy.replaceAll("\\[h ([^\\[]*)\\](.*?)\\[/h\\]", "$2"); // margins formatting: [m 0.5] becomes <span style="margin-left:0.5cm;margin-right:0.5cm"> // dummy = dummy.replaceAll("\\[m ([^\\[]*)\\]([^\\[]*)\\[/m\\]", "<div style=\"margin-left:$1cm;margin-right:$1cm\">$2</div>"); dummy = dummy.replaceAll("\\[m ([^\\[]*)\\](.*?)\\[/m\\]", Matcher.quoteReplacement("\\vspace{$1 cm}$2")); // fix image tags, needed due to manual resizing with "|"., // so the regex below works dummy = fixImageTags(dummy); // image tag: [img]img/gfx.png[/img] becomes <img src="/img/gfx.png"> // first insert the path to the image folder inside the img-src. dummy = dummy.replace("[img]", "[img]" + imgpath); dummy = dummy.replaceAll("\\[img\\]([^|]*)(.*?)\\[/img\\]", Matcher.quoteReplacement("\\includegraphics{") + "$1" + "}"); // unordered list: [l] becomes <ul> dummy = dummy.replaceAll("\\[l\\](.*?)\\[/l\\]", Matcher.quoteReplacement("\\begin{itemize}") + System.getProperty("line.separator") + "$1" + Matcher.quoteReplacement("\\end{itemize}")); // ordered list: [ol] becomes <ol> dummy = dummy.replaceAll("\\[n\\](.*?)\\[/n\\]", Matcher.quoteReplacement("\\begin{enumerate}") + System.getProperty("line.separator") + "$1" + Matcher.quoteReplacement("\\end{enumerate}")); // bullet points: [*] becomes <li> dummy = dummy.replaceAll("\\[\\*\\](.*?)\\[/\\*\\]", Matcher.quoteReplacement("\\item ") + "$1" + System.getProperty("line.separator")); // konvertierung von sonderzeichen dummy = dummy.replace("...", "\\dots"); // here we convert all author-footnotes to latex-cite-tags dummy = ExportTools.createLatexFootnotes(dataObj, dummy, useFootnoteRef); // replace all remaining footnotes without bibkey: [fn 102] becomes (FN xx) dummy = convertFootnotes(dataObj, bibtexObj, settings, dummy, true); // convert tables in tex-format dummy = convertTablesToTex(dummy, settings); // convert form-tags dummy = convertForms(settings, dataObj, dummy, Constants.EXP_TYPE_TEX, createFormTag, true); return dummy; } /** * This method returns the remarks of a current entry in HTML-format, so it is ready to use * for displaying in a jEditorPane. * * @param settings a reference to the CSettings-class * @param text the remarks-text, i.e. the entry's remark * @return the entry's remark-text converted into HTML, for displaying in a jEditorPane */ public static String getHtmlBookmarksComment(Settings settings, String text) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's entry remarks field StringBuilder retval = new StringBuilder(""); // first of all, prepare the header and style information of the main content retval.append("<style>").append(System.getProperty("line.separator")); // body-tag with main font settings // body-tag with main font settings retval.append("body{font-family:"); retval.append(settings.getRemarksFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getRemarksFont(Settings.FONTSIZE)); retval.append("px;color:#"); retval.append(settings.getRemarksFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getRemarksFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getRemarksFont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // copy css-style to retval... retval.append(getHighlightCSS(settings)); retval.append(".content{padding:3px}").append(System.getProperty("line.separator")); // css for links, usually only footnotes. retval.append("a{color:#003399;text-decoration:none}").append(System.getProperty("line.separator")); retval.append("</style>"); // now start with the html content itself retval.append("<div class=\"content\">"); // if we have remarks, replace all return-ubb-tags into html-tags if (!text.isEmpty()) { // now copy the content of the entry to a dummy string. here we convert // the format codes into html-tags. the format codes are simplified tags // for the user to enable simple format editing String dummy = text.replace("<", "<").replace(">", ">").replace("[br]", "<br>"); // if parameters in the string array highlight-terms have been passed, we assume that // these terms should be highlighted... dummy = highlightSearchTerms(dummy, HIGHLIGHT_STYLE_LIVESEARCH); dummy = highlightSearchTerms(dummy, HIGHLIGHT_STYLE_LIVESEARCH); // autoconvert url's to hyperlinks dummy = convertHyperlinks(dummy); // after the conversion is done, append the content to the resulting return string retval.append(dummy); } // close all tags properly retval.append("</div>").append(System.getProperty("line.separator")); return retval.toString(); } public static String getLinkedEntriesAsHtml(Settings settings, List<String> entries, String resmapstring) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's entry remarks field StringBuilder retval = new StringBuilder(""); // first of all, prepare the header and style information of the main content retval.append("<style>").append(System.getProperty("line.separator")); // body-tag with main font settings // body-tag with main font settings retval.append("body{font-family:"); retval.append(settings.getEntryHeaderFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getEntryHeaderFont(Settings.FONTSIZE)); retval.append("px;color:black;font-style:"); retval.append(settings.getEntryHeaderFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getEntryHeaderFont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); retval.append("table{border-collapse:collapse;border:none}").append(System.getProperty("line.separator")); retval.append("td{border:none}").append(System.getProperty("line.separator")); // css for links, usually only footnotes. retval.append("a{color:black;text-decoration:none}").append(System.getProperty("line.separator")); retval.append("</style>"); // now start with the html content itself retval.append("<table><tr>").append(System.getProperty("line.separator")); retval.append("<td width=\"1%\" valign=\"top\">"); retval.append(resourceMap.getString(resmapstring)); retval.append("</td><td valign=\"top\">"); if (entries != null && !entries.isEmpty()) { StringBuilder entrysb = new StringBuilder(""); Iterator<String> i = entries.iterator(); while (i.hasNext()) { String entry = i.next(); entrysb.append("<a href=\"#cr_").append(entry).append("\">").append(entry).append("</a>") .append(" · "); } // append string, but delete last 10 chars, which are " · " retval.append(entrysb.toString().substring(0, entrysb.length() - 10)); } // close all tags properly retval.append("</td></tr></table>").append(System.getProperty("line.separator")); return retval.toString(); } /** * This method creates a common style-sheet for the basic tags, mainly the different * font-settings. since we use this style-definition for several purposes (desktop, main * window...), we have "outsourced" this part to this method. it is called from "getEntryAsHTML" * and "getHtmlContentForDesktop". * * @param settings a reference to the CSettings-class * @param segmentKeywords a String-Array containing keywords that have been assigned to text segements. These * text segements or paragraphs will be highlighted in case a keyword is selected. * @param entrykeywords * @param isDesktop true, when the style-definition is used for the CDesktop-frame, false otherwise * @param isExport true, when the style-definition is used for exporting data, false otherwise * @return the style-definitions for the basic-tags in HTML-CSS-Format */ private static String getCommonStyleDefinition(Settings settings, String[] segmentKeywords, String[] entrykeywords, boolean isDesktop, boolean isExport) { StringBuilder retval = new StringBuilder(getCommonStyleDefinition(settings, isDesktop, isExport, false)); if (segmentKeywords != null && segmentKeywords.length > 0) { for (String sk : segmentKeywords) { sk = sk.replace(" ", "_").replace(":", "_").replace("/", "_").replace("", "ss") .replace("", "ae").replace("", "oe").replace("", "ue").replace("", "Ae") .replace("", "Oe").replace("", "Ue").replace("\\", "_"); retval.append(".highlight_").append(sk).append("{"); retval.append("background-color:#") .append(settings.getHighlightBackgroundColor(HIGHLIGHT_STYLE_KEYWORDS)).append("}"); retval.append(System.getProperty("line.separator")); } if (entrykeywords != null && entrykeywords.length > 0) { LinkedList<String> eks = new LinkedList<String>(); eks.addAll(Arrays.asList(entrykeywords)); for (String sk : segmentKeywords) { eks.remove(sk); } Iterator<String> eki = eks.iterator(); while (eki.hasNext()) { String ek = eki.next(); ek = ek.replace(" ", "_").replace(":", "_").replace("/", "_").replace("", "ss") .replace("", "ae").replace("", "oe").replace("", "ue").replace("", "Ae") .replace("", "Oe").replace("", "Ue").replace("\\", "_"); retval.append(".highlight_").append(ek).append("{"); retval.append("background-color:#ffffff}"); retval.append(System.getProperty("line.separator")); } } } return retval.toString(); } /** * This method creates a common style-sheet for the basic tags, mainly the different * font-settings. since we use this style-definition for several purposes (desktop, main * window...), we have "outsourced" this part to this method. it is called from "getEntryAsHTML" * and "getHtmlContentForDesktop". * * @param settings a reference to the CSettings-class * @param isDesktop true, when the style-definition is used for the CDesktop-frame, false otherwise * @param isExport true, when the style-definition is used for exporting data, false otherwise * @param isPrint * @return the style-definitions for the basic-tags in HTML-CSS-Format */ public static String getCommonStyleDefinition(Settings settings, boolean isDesktop, boolean isExport, boolean isPrint) { // check whether we have custom css settings if (settings.getUseCustomCSS((isDesktop) ? Settings.CUSTOM_CSS_DESKTOP : Settings.CUSTOM_CSS_ENTRY)) { // retrieve custom style sheet String customCss = settings .getCustomCSS((isDesktop) ? Settings.CUSTOM_CSS_DESKTOP : Settings.CUSTOM_CSS_ENTRY); // check for valid value if (customCss != null && !customCss.isEmpty()) return customCss; } // constant defining the padding for all content final String contentpadding = (PlatformUtil.isMacOS()) ? "padding:8px" : "padding:5px"; final String halfcontentpadding = (PlatformUtil.isMacOS()) ? "4" : "2"; // init string builder StringBuilder retval = new StringBuilder(""); // remember, since the desktop has bullets, that these bullets are now // the html-tag "h1", so each title/header of this entries moves one level deeper, i,e, // h1 becomes h2, h2 becomes h3 and so on... String h1 = (isDesktop) ? "h2" : "h1"; String h2 = (isDesktop) ? "h3" : "h2"; String h3 = (isDesktop) ? "h4" : "h3"; String fontunit = (isExport || isPrint) ? "pt" : "px"; /* * CSS for the body */ retval.append("body{font-family:"); // if we print content, use times / serif fonts // body-tag with main font settings if (isPrint) { retval.append("Times New Roman,serif"); } else { retval.append(settings.getMainfont(Settings.FONTNAME)); } retval.append(";font-size:"); retval.append(settings.getMainfont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getMainfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getMainfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getMainfont(Settings.FONTWEIGHT)); // line-height currently not supported by Java // retval.append(";line-height:18px"); retval.append("}").append(System.getProperty("line.separator")); /* * table formatting */ if (settings.getShowTableBorder()) { retval.append( "table{border-collapse:collapse;border-top:1px solid black;border-bottom:1px solid black;padding:0px}") .append(System.getProperty("line.separator")); retval.append(".rowhead{border-top:1px solid black;border-bottom:1px solid black;background-color:#") .append(settings.getTableHeaderColor()).append("}") .append(System.getProperty("line.separator")); } else { retval.append("table{border-collapse:collapse;border:none}") .append(System.getProperty("line.separator")); retval.append(".rowhead{background-color:#").append(settings.getTableHeaderColor()).append("}") .append(System.getProperty("line.separator")); } retval.append("th{padding:4px;border:none;font-weight:bold;"); retval.append("background-color:#").append(settings.getTableHeaderColor()).append("}") .append(System.getProperty("line.separator")); retval.append("td{padding:4px;vertical-align:top}").append(System.getProperty("line.separator")); retval.append(".roweven{background-color:#").append(settings.getTableRowEvenColor()).append("}") .append(System.getProperty("line.separator")); retval.append(".rowodd{background-color:#").append(settings.getTableRowOddColor()).append("}") .append(System.getProperty("line.separator")); retval.append(".tfirstcol{text-align:left}").append(System.getProperty("line.separator")); retval.append(".tothercol{text-align:center}").append(System.getProperty("line.separator")); retval.append("caption{font-style:italic}").append(System.getProperty("line.separator")); /* * header tags formatting */ retval.append(h1); retval.append("{font-family:"); retval.append(settings.getTitleFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getTitleFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getTitleFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getTitleFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getTitleFont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // h2-tag with header1 font settings retval.append(h2); retval.append("{font-family:"); retval.append(settings.getHeaderfont1(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getHeaderfont1(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getHeaderfont1(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getHeaderfont1(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getHeaderfont1(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // h3-tag with header2 font settings retval.append(h3); retval.append("{font-family:"); retval.append(settings.getHeaderfont2(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getHeaderfont2(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getHeaderfont2(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getHeaderfont2(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getHeaderfont2(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); /* * append style-definition for lists */ retval.append("ul{margin-left:10px}").append(System.getProperty("line.separator")); retval.append("ol{margin-left:10px}").append(System.getProperty("line.separator")); // append style-definition for lists retval.append("li{margin-bottom:"); // now we have to calculated a prop ortional line-distance. we do this // by dividing the font-size by 1.5, which is the margin-distance from // each list-point int s = Integer.parseInt(settings.getMainfont(Settings.FONTSIZE)); retval.append(String.valueOf((s / 2))).append(fontunit).append("}") .append(System.getProperty("line.separator")); /* * css for links, usually only footnotes. */ retval.append("a{color:#"); retval.append(settings.getLinkColor()); retval.append(";text-decoration:none}").append(System.getProperty("line.separator")); retval.append("a.manlink{color:#"); retval.append(settings.getManlinkColor()); retval.append(";text-decoration:none}").append(System.getProperty("line.separator")); retval.append("a.fnlink{color:#"); retval.append(settings.getFootnoteLinkColor()); retval.append(";text-decoration:none}").append(System.getProperty("line.separator")); /* * css for different character formattings */ // make footnotes a bit smaller retval.append("sup{font-size:0.9em}").append(System.getProperty("line.separator")); retval.append("sub{font-size:0.9em}").append(System.getProperty("line.separator")); // create style for quotes if (isExport) { retval.append("blockquote"); } else { retval.append(".zitat"); } retval.append("{padding:0.2cm;margin-left:0.2cm;margin-right:0.2cm;background-color:#") .append(settings.getQuoteBackgroundColor()).append(";"); retval.append("font-family:"); retval.append(settings.getQuoteFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getQuoteFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getQuoteFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); // create style for code retval.append("code"); retval.append("{font-family:"); retval.append(settings.getCodeFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getCodeFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getCodeFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); /* * css style for reference list fonts */ retval.append(".reflist{font-family:"); retval.append(settings.getAuthorFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getAuthorFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getAuthorFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getAuthorFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getAuthorFont(Settings.FONTWEIGHT)); retval.append(";margin-bottom:"); // now we have to calculated a proportional line-distance. we do this // by dividing the font-size by 1.5, which is the margin-distance from // each list-point s = Integer.parseInt(settings.getAuthorFont(Settings.FONTSIZE)); float f = (float) (s / 2); retval.append(String.valueOf((int) Math.ceil(f))).append("px}") .append(System.getProperty("line.separator")); /* * css style for search term highlighting */ retval.append(getHighlightCSS(settings)); /*************************************************************** * css style desktop display ***************************************************************/ if (isDesktop) { retval.append("table.maintable{border-collapse:collapse;border:none}") .append(System.getProperty("line.separator")); retval.append(".content{").append(contentpadding).append("}") .append(System.getProperty("line.separator")); // desktop bullet settings retval.append("h1{font-family:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getDesktopHeaderfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // paragraph settings retval.append("p{margin-bottom:6px;margin-top:3px}").append(System.getProperty("line.separator")); // desktop-comment settings retval.append(".comment{padding:5px;background-color:#f0f0f0;"); if (!isExport) { retval.append("padding-top:25px;"); } retval.append("font-family:"); retval.append(settings.getDesktopCommentfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopCommentfont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getDesktopCommentfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopCommentfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopCommentfont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // desktop header font for the display items retval.append(".items{font-family:"); retval.append(settings.getDesktopItemHeaderfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopItemHeaderfont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getDesktopItemHeaderfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopItemHeaderfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopItemHeaderfont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); // desktop font for the display items text retval.append(".itemfont{font-family:"); retval.append(settings.getDesktopItemfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopItemfont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getDesktopItemfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopItemfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopItemfont(Settings.FONTWEIGHT)); retval.append(";margin-top:3px;margin-bottom:3px"); retval.append("}").append(System.getProperty("line.separator")); } /*************************************************************** * css style entry display ***************************************************************/ else { /* * css style for rating-area */ retval.append(".entryrating{background-color:#").append(settings.getEntryHeadingBackgroundColor()) .append(";"); retval.append(contentpadding).append(";font-family:"); retval.append(settings.getEntryHeaderFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getEntryHeaderFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getEntryHeaderFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); retval.append(".elink, .tslink, .rlink {color:#"); retval.append(settings.getEntryHeaderFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); retval.append(".crtitle{margin:0px;padding:0px;width:1%;vertical-align:top;padding-top:") .append(halfcontentpadding).append("px}").append(System.getProperty("line.separator")); retval.append(".crtitle a{color:#"); retval.append(settings.getEntryHeaderFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); retval.append(".mlink {margin:0px;padding:0px;padding-top:").append(halfcontentpadding).append("px}") .append(System.getProperty("line.separator")); retval.append(".mlink a{color:#"); retval.append(settings.getEntryHeaderFont(Settings.FONTCOLOR)).append("}") .append(System.getProperty("line.separator")); retval.append(".tabentryrating{border-collapse:collapse;border:none;margin:0px;padding:0px;width:100%}") .append(System.getProperty("line.separator")); retval.append(".leftcellentryrating{margin:0px;padding:0px;width:30%}") .append(System.getProperty("line.separator")); retval.append(".midcellentryrating{margin:0px;padding:0px;width:45%}") .append(System.getProperty("line.separator")); retval.append(".rightcellentryrating{margin:0px;padding:0px;width:25%}") .append(System.getProperty("line.separator")); retval.append(".content{background-color:#"); retval.append(settings.getContentBackgroundColor()).append(";"); retval.append(contentpadding).append(";padding-bottom:20px}") .append(System.getProperty("line.separator")); /* * css style for appendix */ retval.append(".appendixcontent{background-color:#"); retval.append(settings.getAppendixBackgroundColor()).append(";"); retval.append(contentpadding).append("}").append(System.getProperty("line.separator")); // appendix header retval.append(".appendixcontent h1"); retval.append("{font-family:"); retval.append(settings.getAppendixHeaderFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getAppendixHeaderFont(Settings.FONTSIZE)); retval.append(fontunit).append(";color:#"); retval.append(settings.getAppendixHeaderFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getAppendixHeaderFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getAppendixHeaderFont(Settings.FONTWEIGHT)); retval.append(";margin:0;padding:0}").append(System.getProperty("line.separator")); // h1-tag with title font settings retval.append(".attachments ul{color:#"); retval.append(settings.getLinkColor()); retval.append(";font-size:9").append(fontunit).append(";margin-left:10px}") .append(System.getProperty("line.separator")); retval.append(".attachments ul a{color:#"); retval.append(settings.getLinkColor()); retval.append(";text-decoration:none}").append(System.getProperty("line.separator")); /* * css style for remarks-area in appendix */ retval.append(".remarks{font-family:"); retval.append(settings.getRemarksFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getRemarksFont(Settings.FONTSIZE)); retval.append("px;color:#"); retval.append(settings.getRemarksFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getRemarksFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getRemarksFont(Settings.FONTWEIGHT)); retval.append(";margin-top:"); s = Integer.parseInt(settings.getRemarksFont(Settings.FONTSIZE)); f = (float) (s / 2); retval.append(String.valueOf((int) Math.ceil(f))).append("px}") .append(System.getProperty("line.separator")); } return retval.toString(); } /** * This method return the html-header, i.e. the style-definitions, for the desktop- * window. in contrary to the main window, where each entry gets its own header, because * the html-page in the editorpane consists of just one entry, we have many entries in * one editorpane in the desktop-window - but we need the style-definition only once. * Thus, this method is seperated from the other method, which creates the html-content * of an entry (see "getHtmlContentForDesktop" for further details). * * @param settings * @param print * @return The style definition for the html-page from the desktop window */ public static String getHtmlHeaderForDesktop(Settings settings, boolean print) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's "entry textfield" StringBuilder retval = new StringBuilder(""); // first of all, prepare the header and style information of the main content retval.append("<style>").append(System.getProperty("line.separator")); // get the common style definition for the basic-tags retval.append(getCommonStyleDefinition(settings, true, false, print)); retval.append("</style>"); return retval.toString(); } /** * This method return the html-header, i.e. the style-definitions, for the export- * html-page. in contrary to the main window, where each entry gets its own header, because * the html-page in the editorpane consists of just one entry, we have many entries in * one editorpane in the desktop-window - but we need the style-definition only once. * Thus, this method is seperated from the other method, which creates the html-content * of an entry. * * @param settings * @return The style definition for the html-page from the desktop window */ public static String getHtmlHeaderForExport(Settings settings) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's "entry textfield" StringBuilder retval = new StringBuilder(""); // first of all, prepare the header and style information of the main content retval.append("<style>").append(System.getProperty("line.separator")); // get the common style definition for the basic-tags retval.append(getCommonStyleDefinition(settings, false, true, false)); // body-tag with main font settings retval.append(".deskhead{font-family:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSIZE)); retval.append("pt;color:#"); retval.append(settings.getDesktopHeaderfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); retval.append(".author{font-family:"); retval.append(settings.getAuthorFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getAuthorFont(Settings.FONTSIZE)); retval.append("pt;color:#"); retval.append(settings.getAuthorFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getAuthorFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getAuthorFont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); retval.append("</style><div class=\"content\">"); return retval.toString(); } /** * This method return the html-header, i.e. the style-definitions, for the export- * html-page. in contrary to the main window, where each entry gets its own header, because * the html-page in the editorpane consists of just one entry, we have many entries in * one editorpane in the desktop-window - but we need the style-definition only once. * Thus, this method is seperated from the other method, which creates the html-content * of an entry. * <br><br> * Since we use a different export-approach when exporting the desktop-data (we pass * a complete html-page as parameter), we need to add html, head, and body-tags within * this method here! * * @param settings * @return The style definition for the html-page from the desktop window */ public static String getHtmlHeaderForDesktopExport(Settings settings) { // create an empty string buffer. this buffer contains the html-string // which is being display in the main window's "entry textfield" StringBuilder retval = new StringBuilder(""); // first of all, prepare the header and style information of the main content retval.append("<html><head><style>").append(System.getProperty("line.separator")); // get the common style definition for the basic-tags retval.append(getCommonStyleDefinition(settings, true, true, false)); // body-tag with main font settings retval.append(".tocheader1 {margin-left:0.5em;}").append(System.getProperty("line.separator")); retval.append(".tocentry1 {margin-left:1em;}").append(System.getProperty("line.separator")); retval.append(".tocheader2 {margin-left:1.5em;}").append(System.getProperty("line.separator")); retval.append(".tocentry2 {margin-left:2em;}").append(System.getProperty("line.separator")); retval.append(".tocheader3 {margin-left:2.5em;}").append(System.getProperty("line.separator")); retval.append(".tocentry3 {margin-left:3em;}").append(System.getProperty("line.separator")); retval.append(".tocheader4 {margin-left:3.5em;}").append(System.getProperty("line.separator")); retval.append(".tocentry4 {margin-left:4em;}").append(System.getProperty("line.separator")); retval.append(".tocheader5 {margin-left:4.5em;}").append(System.getProperty("line.separator")); retval.append(".tocentry5 {margin-left:5em;}").append(System.getProperty("line.separator")); retval.append(".deskhead{font-family:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSIZE)); retval.append("pt;color:#"); retval.append(settings.getDesktopHeaderfont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getDesktopHeaderfont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); retval.append(".author{font-family:"); retval.append(settings.getAuthorFont(Settings.FONTNAME)); retval.append(";font-size:"); retval.append(settings.getAuthorFont(Settings.FONTSIZE)); retval.append("pt;color:#"); retval.append(settings.getAuthorFont(Settings.FONTCOLOR)); retval.append(";font-style:"); retval.append(settings.getAuthorFont(Settings.FONTSTYLE)); retval.append(";font-weight:"); retval.append(settings.getAuthorFont(Settings.FONTWEIGHT)); retval.append("}").append(System.getProperty("line.separator")); retval.append("</style></head><body><div class=\"content\">"); return retval.toString(); } /** * This method creates a html page of the parameters passed to this class constructor * It is easier to keep the overview over the layout style when the html page, which is * responsible for the "look'n'feel" of an entry, is being created in a separate class * rather than in the CDaten class. * <br><br> * This method creates the html-content of entries for the desktop window. * * @param dataObj * @param bibtexObj * @param settings * @param nr * @param isExport * @param isHeadingVisible * @param isEntryNumberVisible * @param createHtmlFootnotes * @return a string with the html-page-content */ public static String getHtmlContentForDesktop(Daten dataObj, BibTex bibtexObj, Settings settings, int nr, boolean isHeadingVisible, boolean isEntryNumberVisible, boolean isExport, boolean createHtmlFootnotes) { // get the zettelcontent return getHtmlContentForDesktop(dataObj, bibtexObj, settings, dataObj.getZettelContent(nr), nr, isHeadingVisible, isEntryNumberVisible, isExport, createHtmlFootnotes); // and replace header-tags, since they change // order when they are put on the desktop // .replace("h3","h4").replace("h2","h3"); } /** * * @param dataObj * @param nr * @param isEntryNumberVisible * @return */ public static String getZettelTitleForDesktop(Daten dataObj, int nr, boolean isEntryNumberVisible) { StringBuilder retval = new StringBuilder(""); // first check whether we have a title or not String zetteltitle = dataObj.getZettelTitle(nr).replace("<", "<").replace(">", ">"); // display title. remember, since the desktop has bullets, that these bullets are now // the html-tag "h1", so each title/header of this entries moves one level deeper, i,e, // h1 becomes h2, h2 becomes h3 and so on... // // each entry has at least the title "entry" plus its number. // we need this to search through the entries when the user clicks an entry on the // jTreeDesktop in the desktop-window // start open-tag for heading 2. level retval.append("<p><strong>"); // if either entry number should be visible, or if no entry title available // the entry-number should be displayed if (isEntryNumberVisible || zetteltitle.isEmpty()) { // retrieve locale entry-text retval.append(resourceMap.getString("entryText")); retval.append(" "); // and add entry-number retval.append(String.valueOf(nr)); } // if we have a "real" title, append it... if (!zetteltitle.isEmpty()) { // don't use a colon, if entry-number should not be visible if (isEntryNumberVisible) { retval.append(": "); } // append title retval.append(zetteltitle); } retval.append("</strong></p>").append(System.getProperty("line.separator")); return retval.toString(); } /** * This method creates a html page of the parameters passed to this class constructor * It is easier to keep the overview over the layout style when the html page, which is * responsible for the "look'n'feel" of an entry, is being created in a separate class * rather than in the CDaten class. * <br><br> * This method creates the html-content of entries for the desktop window. * * @param dataObj * @param bibtexObj * @param settings * @param isHeadingVisible * @param nr * @param zettelcontent * @param isEntryNumberVisible * @param isExport * @param createHtmlFootnotes * @return a string with the html-page-content */ public static String getHtmlContentForDesktop(Daten dataObj, BibTex bibtexObj, Settings settings, String zettelcontent, int nr, boolean isHeadingVisible, boolean isEntryNumberVisible, boolean isExport, boolean createHtmlFootnotes) { // create an empty string buffer. this buffer contains the html-string // which is being display in the desktop window's main textfield StringBuilder retval = new StringBuilder(""); // create entry title if (isHeadingVisible) { retval.append(getZettelTitleForDesktop(dataObj, nr, isEntryNumberVisible)); } // if we have content, convert ubb-tags. if (!zettelcontent.isEmpty()) { // now copy the content of the entry to a dummy string. here we convert // the format codes into html-tags. the format codes are simplified tags // for the user to enable simple format editing String dummy = convertUbbToHtml(settings, dataObj, bibtexObj, zettelcontent, Constants.FRAME_DESKTOP, isExport, createHtmlFootnotes); // after the conversion is done, append the content to the resulting return string retval.append("<p>").append(dummy).append("</p>"); } else { retval.append("<p><i>").append(resourceMap.getString("deletedEntry")).append("</i></p>"); } // // here we setup the remarks // // if the user wants to display authors, display them now... if ((settings.getDesktopDisplayItems() & Constants.DESKTOP_SHOW_REMARKS) != 0) { // get entries remarks String rem = dataObj.getRemarks(nr); // if the entry has remarks, add them to the content if (!rem.isEmpty()) { // set title retval.append(System.getProperty("line.separator")).append("<p class=\"items\">"); retval.append(resourceMap.getString("remarksText")); retval.append("</p>").append(System.getProperty("line.separator")).append("<p class=\"itemfont\">"); // now copy the content of the entry to a dummy string. here we convert // the format codes into html-tags. the format codes are simplified tags // for the user to enable simple format editing rem = rem.replace("<", "<").replace(">", ">").replace("[br]", "<br>"); // after the conversion is done, append the content to the resulting return string retval.append(rem); retval.append("</p>").append(System.getProperty("line.separator")); } } // // here we setup the authors // // if the user wants to display authors, display them now... if ((settings.getDesktopDisplayItems() & Constants.DESKTOP_SHOW_AUTHORS) != 0) { // get entry's authors String[] zettelauthors = dataObj.getAuthors(nr); // if there is no author information, tell this the user if ((zettelauthors != null) && (zettelauthors.length > 0)) { // set title retval.append(System.getProperty("line.separator")).append("<p class=\"items\">"); retval.append(resourceMap.getString("authorsText")); retval.append("</p>"); // iterate the author array for (String aus : zettelauthors) { // autoconvert url's to hyperlinks aus = convertHyperlinks(aus.replace("<", "<").replace(">", ">")); // and append each author retval.append(System.getProperty("line.separator")).append("<p class=\"itemfont\">").append(aus) .append("</p>"); } retval.append(System.getProperty("line.separator")); } } // // here we setup the attachments // // if the user wants to display authors, display them now... if ((settings.getDesktopDisplayItems() & Constants.DESKTOP_SHOW_ATTACHMENTS) != 0) { // get entry's attachments List<Element> links = dataObj.getAttachments(nr); // if there is no author information, tell this the user if ((links != null) && (!links.isEmpty())) { // set title retval.append(System.getProperty("line.separator")).append("<p class=\"items\">"); retval.append(resourceMap.getString("attachmentsText")); retval.append("</p>").append(System.getProperty("line.separator")).append("<p class=\"itemfont\">"); // create iterator Iterator<Element> ie = links.iterator(); // iterate the list while (ie.hasNext()) { Element e = ie.next(); // and append each attachment retval.append("<a href=\"").append(e.getText()).append("\">").append(e.getText()) .append("</a><br>").append(System.getProperty("line.separator")); } retval.append("</p>").append(System.getProperty("line.separator")); } } // // here we setup the keywords // // if the user wants to display authors, display them now... if ((settings.getDesktopDisplayItems() & Constants.DESKTOP_SHOW_KEYWORDS) != 0) { // get entry's keywords String[] kws = dataObj.getKeywords(nr); // if there is no author information, tell this the user if ((kws != null) && (kws.length > 0)) { // set title retval.append(System.getProperty("line.separator")).append("<p class=\"items\">"); retval.append(resourceMap.getString("keywordsText")); retval.append("</p>").append(System.getProperty("line.separator")).append("<p class=\"itemfont\">"); // sort array Arrays.sort(kws, new Comparer()); // iterate the string arryy // and append each keyword for (String k : kws) { retval.append(k).append(", "); } // truncate last comma and space retval.setLength(retval.length() - 2); // close tag retval.append("</p>").append(System.getProperty("line.separator")); } } // return finished entry return retval.toString(); } }