/* * WPCleaner: A tool to help on Wikipedia maintenance tasks. * Copyright (C) 2013 Nicolas Vervelle * * See README.txt file for licensing information. */ package org.wikipediacleaner.gui.swing.component; import java.util.List; import java.util.UUID; import javax.swing.text.Style; import javax.swing.text.StyledDocument; import org.wikipediacleaner.api.constants.EnumWikipedia; import org.wikipediacleaner.api.constants.WPCConfigurationStringList; import org.wikipediacleaner.api.data.Page; import org.wikipediacleaner.api.data.PageAnalysis; import org.wikipediacleaner.api.data.PageElementComment; import org.wikipediacleaner.api.data.PageElementInternalLink; import org.wikipediacleaner.api.data.PageElementTemplate; import org.wikipediacleaner.api.data.TemplateMatcher; import org.wikipediacleaner.utils.ConfigurationValueStyle; /** * A disambiguation formatter for MediaWikiPane. */ public class MWPaneDisambiguationFormatter extends MWPaneFormatter { private final EnumWikipedia wikipedia; /** * Construct a disambiguation formatter. * * @param wikipedia Wikipedia. * @param links Links of interest. */ public MWPaneDisambiguationFormatter( EnumWikipedia wikipedia, List<Page> links) { this.wikipedia = wikipedia; this.links = links; } /** * Format text in a StyleDocument. * * @param doc Document to be formatted. * @param pageAnalysis Page analysis. */ @Override public void format(StyledDocument doc, PageAnalysis pageAnalysis) { // Clean formatting cleanFormat(doc); // Reset caret informations resetCaretPosition(); // Format comments defaultFormatElements(doc, pageAnalysis); // Format internal links formatInternalLinks(doc, pageAnalysis); // Format templates formatTemplates(doc, pageAnalysis); } /** * Format internal links in a MediaWikiPane. * * @param doc Document to be formatted. * @param pageAnalysis Page analysis. */ private void formatInternalLinks( StyledDocument doc, PageAnalysis pageAnalysis) { if ((doc == null) || (pageAnalysis == null)) { return; } for (PageElementInternalLink link : pageAnalysis.getInternalLinks()) { formatInternalLink(doc, link, pageAnalysis); } } /** * Format an internal link in a MediaWikiPane. * * @param doc Document to be formatted. * @param internalLink Internal link to be formatted. * @param pageAnalysis Page analysis. */ private void formatInternalLink( StyledDocument doc, PageElementInternalLink internalLink, PageAnalysis pageAnalysis) { // Basic verifications if ((doc == null) || (internalLink == null)) { return; } // Check if the link should be formatted Page link = findPage(internalLink.getLink()); if (link == null) { return; } // Format the link String contents = pageAnalysis.getContents(); boolean disambiguation = Boolean.TRUE.equals(link.isDisambiguationPage()); String text = internalLink.getDisplayedText(); int start = internalLink.getBeginIndex(); int end = internalLink.getEndIndex(); while ((end < contents.length()) && (Character.isLetter(contents.charAt(end))) && (Character.getType(contents.charAt(end)) != Character.OTHER_LETTER)) { end++; } if (end > internalLink.getEndIndex()) { text = text + contents.substring(internalLink.getEndIndex(), end); } ConfigurationValueStyle styleType = null; if (disambiguation) { styleType = ConfigurationValueStyle.INTERNAL_LINK_DAB; // Check if a template is after the link to ask for help List<String> templatesAfter = wikipedia.getConfiguration().getStringList( WPCConfigurationStringList.TEMPLATES_AFTER_HELP_ASKED); if ((templatesAfter != null) && !templatesAfter.isEmpty()) { int maxSize = contents.length(); int currentPos = end; while ((currentPos < maxSize) && (contents.charAt(currentPos) == ' ')) { currentPos++; } if ((currentPos < maxSize) && (contents.charAt(currentPos) == '{')) { PageElementTemplate nextTemplate = pageAnalysis.isInTemplate(currentPos); if (nextTemplate != null) { for (String templateAfter : templatesAfter) { if (Page.areSameTitle(templateAfter, nextTemplate.getTemplateName())) { styleType = ConfigurationValueStyle.HELP_REQUESTED; end = nextTemplate.getEndIndex(); } } } } } List<String> commentsAfter = wikipedia.getConfiguration().getStringList( WPCConfigurationStringList.COMMENTS_FOR_DAB_LINK); if ((commentsAfter != null) && !commentsAfter.isEmpty()) { int maxSize = contents.length(); int currentPos = end; while ((currentPos < maxSize) && (contents.charAt(currentPos) == ' ')) { currentPos++; } if ((currentPos < maxSize) && (contents.charAt(currentPos) == '<')) { PageElementComment comment = pageAnalysis.isInComment(currentPos); if (comment != null) { for (String commentAfter : commentsAfter) { String comment2 = comment.getComment(); if ((comment2 != null) && (comment2.length() >= commentAfter.length())) { comment2 = comment2.substring(0, commentAfter.length()); if (comment2.equalsIgnoreCase(commentAfter)) { styleType = ConfigurationValueStyle.INTERNAL_LINK_NORMAL; end = comment.getEndIndex(); } } } } } } } else if (link.isRedirect()) { styleType = ConfigurationValueStyle.INTERNAL_LINK_REDIRECT; } else if (Boolean.TRUE.equals(link.isExisting())) { styleType = ConfigurationValueStyle.INTERNAL_LINK_NORMAL; } else { styleType = ConfigurationValueStyle.INTERNAL_LINK_MISSING; } Style attr = doc.getStyle(styleType.getName()); if (attr == null) { return; } attr = (Style) attr.copyAttributes(); attr.addAttribute(ATTRIBUTE_PAGE, link); attr.addAttribute(ATTRIBUTE_TEXT, text); attr.addAttribute(ATTRIBUTE_UUID, UUID.randomUUID()); doc.setCharacterAttributes(start, end - start, attr, true); if (start < startPosition) { startPosition = start; endPosition = end; } } /** * Format templates in a MediaWikiPane. * * @param doc Document to be formatted. * @param pageAnalysis Page analysis. */ private void formatTemplates( StyledDocument doc, PageAnalysis pageAnalysis) { if (pageAnalysis == null) { return; } for (PageElementTemplate template : pageAnalysis.getTemplates()) { formatTemplate(doc, pageAnalysis, template); } } /** * Format a template in a MediaWikiPane. * * @param doc Document to be formatted. * @param pageAnalysis Page analysis. * @param template Template to be formatted. */ private void formatTemplate( StyledDocument doc, PageAnalysis pageAnalysis, PageElementTemplate template) { // Basic verifications if ((doc == null) || (pageAnalysis == null) || (template == null) || (links == null)) { return; } // Check if the link should be formatted String templateName = template.getTemplateName(); List<? extends TemplateMatcher> matchers = wikipedia.getConfiguration().getTemplateMatchers(templateName); if (matchers == null) { return; } for (TemplateMatcher matcher : matchers) { String linkTo = matcher.linksTo(pageAnalysis.getPage(), template); if (linkTo != null) { Page link = findPage(linkTo); if (link != null) { formatTemplate(doc, link, template, matcher); return; } } } } /** * Format a template in a MediaWikiPane. * * @param doc Document to be formatted. * @param link Page linked. * @param template Template to be formatted. * @param matcher Template matcher. */ private void formatTemplate( StyledDocument doc, Page link, PageElementTemplate template, TemplateMatcher matcher) { // Basic verifications if ((doc == null) || (template == null) || (matcher == null)) { return; } // Format template if (matcher.isGood() || Boolean.FALSE.equals(link.isDisambiguationPage())) { formatTemplateGood(doc, link, template, matcher); } else if (matcher.isHelpNeeded()) { formatTemplateHelpRequested(doc, link, template, matcher); } else { formatTemplateDisambiguation(doc, link, template, matcher); } } /** * Format a template in a MediaWikiPane. * * @param doc Document to be formatted. * @param link Page linked. * @param template Template to be formatted. * @param matcher Template matcher. */ private void formatTemplateGood( StyledDocument doc, Page link, PageElementTemplate template, TemplateMatcher matcher) { // Basic verifications if ((doc == null) || (template == null) || (matcher == null)) { return; } // Format template int start = template.getBeginIndex(); int end = template.getEndIndex(); Style attr = doc.getStyle(ConfigurationValueStyle.TEMPLATE_NORMAL.getName()); attr = (Style) attr.copyAttributes(); attr.addAttribute(ATTRIBUTE_PAGE, link); attr.addAttribute(ATTRIBUTE_PAGE_ELEMENT, template); attr.addAttribute(ATTRIBUTE_TEMPLATE_MATCHER, matcher); attr.addAttribute(ATTRIBUTE_UUID, UUID.randomUUID()); doc.setCharacterAttributes(start, end - start, attr, true); if (start < thirdStartPosition) { thirdStartPosition = start; thirdEndPosition = end; } } /** * Format a template in a MediaWikiPane. * * @param doc Document to be formatted. * @param link Page linked. * @param template Template to be formatted. * @param matcher Template matcher. */ private void formatTemplateHelpRequested( StyledDocument doc, Page link, PageElementTemplate template, TemplateMatcher matcher) { // Basic verifications if ((doc == null) || (template == null) || (matcher == null)) { return; } // Format template int start = template.getBeginIndex(); int end = template.getEndIndex(); Style attr = doc.getStyle(ConfigurationValueStyle.HELP_REQUESTED.getName()); attr = (Style) attr.copyAttributes(); attr.addAttribute(ATTRIBUTE_PAGE, link); attr.addAttribute(ATTRIBUTE_UUID, UUID.randomUUID()); if (template.getParameterCount() > 0) { attr.addAttribute( ATTRIBUTE_TEXT, (template.getParameterCount() > 1) ? template.getParameterValue(1) : template.getParameterValue(0)); } else { attr.addAttribute(ATTRIBUTE_PAGE_ELEMENT, template); attr.addAttribute(ATTRIBUTE_TEMPLATE_MATCHER, matcher); } doc.setCharacterAttributes(start, end - start, attr, true); if (start < secondStartPosition) { secondStartPosition = start; secondEndPosition = end; } } /** * Format a template in a MediaWikiPane. * * @param doc Document to be formatted. * @param link Page linked. * @param template Template to be formatted. * @param matcher Template matcher. */ private void formatTemplateDisambiguation( StyledDocument doc, Page link, PageElementTemplate template, TemplateMatcher matcher) { // Basic verifications if ((doc == null) || (template == null) || (matcher == null)) { return; } // Format template int start = template.getBeginIndex(); int end = template.getEndIndex(); Style attr = doc.getStyle(ConfigurationValueStyle.TEMPLATE_DAB.getName()); attr = (Style) attr.copyAttributes(); attr.addAttribute(ATTRIBUTE_PAGE, link); attr.addAttribute(ATTRIBUTE_PAGE_ELEMENT, template); attr.addAttribute(ATTRIBUTE_TEMPLATE_MATCHER, matcher); attr.addAttribute(ATTRIBUTE_UUID, UUID.randomUUID()); doc.setCharacterAttributes(start, end - start, attr, true); if (start < startPosition) { startPosition = start; endPosition = end; } } /* ======================================================================== */ /* Caret management */ /* ======================================================================== */ private int startPosition; private int endPosition; private int secondStartPosition; private int secondEndPosition; private int thirdStartPosition; private int thirdEndPosition; /** * Reset caret positions. */ private void resetCaretPosition() { startPosition = Integer.MAX_VALUE; endPosition = Integer.MAX_VALUE; secondStartPosition = Integer.MAX_VALUE; secondEndPosition = Integer.MAX_VALUE; thirdStartPosition = Integer.MAX_VALUE; thirdEndPosition = Integer.MAX_VALUE; } /** * Move caret. * * @param pane MediaWikiPane. */ @Override protected void moveCaret(MWPane pane) { if (pane == null) { return; } if (startPosition < Integer.MAX_VALUE) { pane.setCaretPosition(startPosition); pane.moveCaretPosition(endPosition); } else if (secondStartPosition < Integer.MAX_VALUE) { pane.setCaretPosition(secondStartPosition); pane.moveCaretPosition(secondEndPosition); } else if (thirdStartPosition < Integer.MAX_VALUE) { pane.setCaretPosition(thirdStartPosition); pane.moveCaretPosition(thirdEndPosition); } } /* ======================================================================== */ /* Links management */ /* ======================================================================== */ /** * List of links of interest. */ private final List<Page> links; /** * Find the page matching a page name. * * @param pagename Page name. * @return Page matching the page name. */ private Page findPage(String pagename) { if (links != null) { for (Page page : links) { if (Page.areSameTitle(page.getTitle(), pagename)) { return page; } } } return null; } /** * @param pages List of pages. * @return True if the list is identical. */ public boolean isSameList(List<Page> pages) { if ((pages == null) || (links == null)) { return false; } return pages.equals(links); } }