Java tutorial
/* LanguageTool, a natural language style checker * Copyright (C) 2012 Daniel Naber (http://www.danielnaber.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ package org.languagetool.gui; import java.awt.Cursor; import java.awt.Desktop; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; import java.util.Set; import javax.swing.JTextPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import org.apache.commons.lang.StringUtils; import org.languagetool.Language; import org.languagetool.rules.ITSIssueType; import org.languagetool.rules.Rule; import org.languagetool.rules.RuleMatch; import org.languagetool.tools.ContextTools; import org.languagetool.tools.StringTools; /** * Area where the result of text checking is displayed. */ class ResultArea { private static final String DEACTIVATE_URL = "http://languagetool.org/deactivate/"; private static final String REACTIVATE_URL = "http://languagetool.org/reactivate/"; private static final String LT_ERROR_MARKER_START = "<b><font bgcolor=\"#d7d7ff\">"; private static final String SPELL_ERROR_MARKER_START = "<b><font bgcolor=\"#ffd7d7\">"; private final ResourceBundle messages; private final JTextPane statusPane; private final LanguageToolSupport ltSupport; private final Object marker = new Object(); private String inputText; private String startText; private List<RuleMatch> allRuleMatches; private List<RuleMatch> ruleMatches; // will be filtered to not show disabled rules private long runTime; ResultArea(final ResourceBundle messages, final LanguageToolSupport ltSupport, final JTextPane statusPane) { this.messages = messages; this.ltSupport = ltSupport; this.statusPane = statusPane; statusPane.setContentType("text/html"); statusPane.setText(Main.HTML_GREY_FONT_START + messages.getString("resultAreaText") + Main.HTML_FONT_END); statusPane.setEditable(false); statusPane.addHyperlinkListener(new MyHyperlinkListener()); statusPane.setTransferHandler(new RetainLineBreakTransferHandler()); ltSupport.addLanguageToolListener(new LanguageToolListener() { @Override public void languageToolEventOccurred(LanguageToolEvent event) { if (event.getType() == LanguageToolEvent.Type.CHECKING_STARTED) { final Language lang = ltSupport.getLanguage(); final String langName; if (lang.isExternal()) { langName = lang.getTranslatedName(messages) + Main.EXTERNAL_LANGUAGE_SUFFIX; } else { langName = lang.getTranslatedName(messages); } final String startCheckText = Main.HTML_GREY_FONT_START + Tools.makeTexti18n(messages, "startChecking", langName) + "..." + Main.HTML_FONT_END; statusPane.setText(startCheckText); setStartText(startCheckText); if (event.getCaller() == marker) { statusPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } } else if (event.getType() == LanguageToolEvent.Type.CHECKING_FINISHED) { inputText = event.getSource().getTextComponent().getText(); setRuleMatches(event.getSource().getMatches()); if (event.getCaller() == marker || event.getCaller() == null) { displayResult(); if (event.getCaller() == marker) { statusPane.setCursor(Cursor.getDefaultCursor()); } } } else if (event.getType() == LanguageToolEvent.Type.RULE_DISABLED || event.getType() == LanguageToolEvent.Type.RULE_ENABLED) { inputText = event.getSource().getTextComponent().getText(); setRuleMatches(event.getSource().getMatches()); displayResult(); } } }); } private String getRuleMatchHtml(List<RuleMatch> ruleMatches, String text, String startCheckText) { final ContextTools contextTools = new ContextTools(); final StringBuilder sb = new StringBuilder(200); sb.append(startCheckText); sb.append("<br>\n"); int i = 0; for (final RuleMatch match : ruleMatches) { final String output = Tools.makeTexti18n(messages, "result1", i + 1, match.getLine() + 1, match.getColumn()); sb.append(output); final String msg = match.getMessage().replaceAll("<suggestion>", "<b>") .replaceAll("</suggestion>", "</b>").replaceAll("<old>", "<b>").replaceAll("</old>", "</b>"); sb.append("<b>").append(messages.getString("errorMessage")).append("</b> "); sb.append(msg); final RuleLink ruleLink = RuleLink.buildDeactivationLink(match.getRule()); sb.append(" <a href=\"").append(ruleLink).append("\">").append(messages.getString("deactivateRule")) .append("</a><br>\n"); if (match.getSuggestedReplacements().size() > 0) { final String replacement = StringTools.listToString(match.getSuggestedReplacements(), "; "); sb.append("<b>").append(messages.getString("correctionMessage")).append("</b> ").append(replacement) .append("<br>\n"); } if (ITSIssueType.Misspelling.equals(match.getRule().getLocQualityIssueType())) { contextTools.setErrorMarkerStart(SPELL_ERROR_MARKER_START); } else { contextTools.setErrorMarkerStart(LT_ERROR_MARKER_START); } final String context = contextTools.getContext(match.getFromPos(), match.getToPos(), text); sb.append("<b>").append(messages.getString("errorContext")).append("</b> ").append(context); sb.append("<br>\n"); if (match.getRule().getUrl() != null && Desktop.isDesktopSupported()) { sb.append("<b>").append(messages.getString("moreInfo")).append("</b> <a href=\""); final String url = match.getRule().getUrl().toString(); sb.append(url); final String shortUrl = StringUtils.abbreviate(url, 60); sb.append("\">").append(shortUrl).append("</a><br>\n"); } i++; } sb.append(Main.HTML_GREY_FONT_START); sb.append(getDisabledRulesHtml()); final String checkDone = Tools.makeTexti18n(messages, "checkDone", ruleMatches.size(), runTime); sb.append("<br>\n").append(checkDone); sb.append("<br>\n").append(messages.getString("makeLanguageToolBetter")); sb.append(Main.HTML_FONT_END).append("<br>\n"); return sb.toString(); } private String getDisabledRulesHtml() { final StringBuilder sb = new StringBuilder(40); sb.append(messages.getString("deactivatedRulesText")); int i = 0; int deactivatedRuleCount = 0; for (String ruleId : ltSupport.getConfig().getDisabledRuleIds()) { if (ruleId.trim().isEmpty()) { continue; } final Rule rule = ltSupport.getRuleForId(ruleId); if (rule == null || rule.isDefaultOff()) { continue; } if (i++ > 0) { sb.append(','); } final RuleLink reactivationLink = RuleLink.buildReactivationLink(rule); sb.append(" <a href=\"").append(reactivationLink).append("\">").append(rule.getDescription()) .append("</a>"); deactivatedRuleCount++; } sb.append("<br>"); if (deactivatedRuleCount == 0) { return ""; } else { return sb.toString(); } } private void setStartText(String startText) { this.startText = startText; } void setRunTime(long runTime) { this.runTime = runTime; } void setRuleMatches(List<RuleMatch> ruleMatches) { this.allRuleMatches = new ArrayList<>(ruleMatches); this.ruleMatches = new ArrayList<>(ruleMatches); } void displayResult() { ruleMatches = filterRuleMatches(); final String ruleMatchHtml = getRuleMatchHtml(ruleMatches, inputText, startText); displayText(ruleMatchHtml); } private void displayText(String text) { // TODO: use a JTable for faster rendering statusPane.setText(Main.HTML_FONT_START + text + Main.HTML_FONT_END); statusPane.setCaretPosition(0); } private List<RuleMatch> filterRuleMatches() { final List<RuleMatch> filtered = new ArrayList<>(); final Set<String> disabledRuleIds = ltSupport.getConfig().getDisabledRuleIds(); for (RuleMatch ruleMatch : allRuleMatches) { if (!disabledRuleIds.contains(ruleMatch.getRule().getId())) { filtered.add(ruleMatch); } } return filtered; } private class MyHyperlinkListener implements HyperlinkListener { private MyHyperlinkListener() { } @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { final URL url = e.getURL(); try { final String uri = url.toURI().toString(); if (uri.startsWith(DEACTIVATE_URL) || uri.startsWith(REACTIVATE_URL)) { handleRuleLinkClick(uri); } else { handleHttpClick(url); } } catch (Exception ex) { throw new RuntimeException("Could not handle URL click: " + url, ex); } } } private void handleRuleLinkClick(String uri) throws IOException { final RuleLink ruleLink = RuleLink.getFromString(uri); final String ruleId = ruleLink.getId(); if (uri.startsWith(DEACTIVATE_URL)) { ltSupport.disableRule(ruleId); } else { ltSupport.enableRule(ruleId); } ltSupport.getConfig().saveConfiguration(ltSupport.getLanguage()); ltSupport.checkImmediately(marker); } private void handleHttpClick(URL url) { if (Desktop.isDesktopSupported()) { try { final Desktop desktop = Desktop.getDesktop(); desktop.browse(url.toURI()); } catch (Exception ex) { throw new RuntimeException("Could not open URL: " + url, ex); } } } } }