001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: package com.ecyrd.jspwiki.diff;
022:
023: import java.io.IOException;
024: import java.text.ChoiceFormat;
025: import java.text.Format;
026: import java.text.MessageFormat;
027: import java.text.NumberFormat;
028: import java.util.Properties;
029: import java.util.ResourceBundle;
030:
031: import org.apache.commons.jrcs.diff.*;
032: import org.apache.commons.jrcs.diff.myers.MyersDiff;
033: import org.apache.log4j.Logger;
034:
035: import com.ecyrd.jspwiki.NoRequiredPropertyException;
036: import com.ecyrd.jspwiki.TextUtil;
037: import com.ecyrd.jspwiki.WikiContext;
038: import com.ecyrd.jspwiki.WikiEngine;
039: import com.ecyrd.jspwiki.i18n.InternationalizationManager;
040:
041: /**
042: * This is the JSPWiki 'traditional' diff.
043: * @author Janne Jalkanen
044: * @author Erik Bunn
045: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
046: */
047:
048: public class TraditionalDiffProvider implements DiffProvider {
049: private static final Logger log = Logger
050: .getLogger(TraditionalDiffProvider.class);
051:
052: private static final String CSS_DIFF_ADDED = "<tr><td class=\"diffadd\">";
053: private static final String CSS_DIFF_REMOVED = "<tr><td class=\"diffrem\">";
054: private static final String CSS_DIFF_UNCHANGED = "<tr><td class=\"diff\">";
055: private static final String CSS_DIFF_CLOSE = "</td></tr>" + Diff.NL;
056:
057: public TraditionalDiffProvider() {
058: }
059:
060: /**
061: * @see com.ecyrd.jspwiki.WikiProvider#getProviderInfo()
062: */
063: public String getProviderInfo() {
064: return "TraditionalDiffProvider";
065: }
066:
067: /**
068: * @see com.ecyrd.jspwiki.WikiProvider#initialize(com.ecyrd.jspwiki.WikiEngine, java.util.Properties)
069: */
070: public void initialize(WikiEngine engine, Properties properties)
071: throws NoRequiredPropertyException, IOException {
072: }
073:
074: /**
075: * Makes a diff using the BMSI utility package. We use our own diff printer,
076: * which makes things easier.
077: */
078: public String makeDiffHtml(WikiContext ctx, String p1, String p2) {
079: String diffResult = "";
080:
081: try {
082: String[] first = Diff.stringToArray(TextUtil
083: .replaceEntities(p1));
084: String[] second = Diff.stringToArray(TextUtil
085: .replaceEntities(p2));
086: Revision rev = Diff.diff(first, second, new MyersDiff());
087:
088: if (rev == null || rev.size() == 0) {
089: // No difference
090:
091: return "";
092: }
093:
094: StringBuffer ret = new StringBuffer(rev.size() * 20); // Guessing how big it will become...
095:
096: ret
097: .append("<table class=\"diff\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n");
098: rev.accept(new RevisionPrint(ctx, ret));
099: ret.append("</table>\n");
100:
101: return ret.toString();
102: } catch (DifferentiationFailedException e) {
103: diffResult = "makeDiff failed with DifferentiationFailedException";
104: log.error(diffResult, e);
105: }
106:
107: return diffResult;
108: }
109:
110: public static final class RevisionPrint implements RevisionVisitor {
111: private StringBuffer m_result = null;
112: private WikiContext m_context;
113: private ResourceBundle m_rb;
114:
115: private RevisionPrint(WikiContext ctx, StringBuffer sb) {
116: m_result = sb;
117: m_context = ctx;
118: m_rb = ctx
119: .getBundle(InternationalizationManager.CORE_BUNDLE);
120: }
121:
122: public void visit(Revision rev) {
123: // GNDN (Goes nowhere, does nothing)
124: }
125:
126: public void visit(AddDelta delta) {
127: Chunk changed = delta.getRevised();
128: print(changed, m_rb.getString("diff.traditional.added"));
129: changed.toString(m_result, CSS_DIFF_ADDED, CSS_DIFF_CLOSE);
130: }
131:
132: public void visit(ChangeDelta delta) {
133: Chunk changed = delta.getOriginal();
134: print(changed, m_rb.getString("diff.traditional.changed"));
135: changed
136: .toString(m_result, CSS_DIFF_REMOVED,
137: CSS_DIFF_CLOSE);
138: delta.getRevised().toString(m_result, CSS_DIFF_ADDED,
139: CSS_DIFF_CLOSE);
140: }
141:
142: public void visit(DeleteDelta delta) {
143: Chunk changed = delta.getOriginal();
144: print(changed, m_rb.getString("diff.traditional.removed"));
145: changed
146: .toString(m_result, CSS_DIFF_REMOVED,
147: CSS_DIFF_CLOSE);
148: }
149:
150: private void print(Chunk changed, String type) {
151: m_result.append(CSS_DIFF_UNCHANGED);
152:
153: String[] choiceString = {
154: m_rb.getString("diff.traditional.oneline"),
155: m_rb.getString("diff.traditional.lines") };
156: double[] choiceLimits = { 1, 2 };
157:
158: MessageFormat fmt = new MessageFormat("");
159: fmt.setLocale(WikiContext.getLocale(m_context));
160: ChoiceFormat cfmt = new ChoiceFormat(choiceLimits,
161: choiceString);
162: fmt.applyPattern(type);
163: Format[] formats = { NumberFormat.getInstance(), cfmt,
164: NumberFormat.getInstance() };
165: fmt.setFormats(formats);
166:
167: Object[] params = { new Integer(changed.first() + 1),
168: new Integer(changed.size()),
169: new Integer(changed.size()) };
170: m_result.append(fmt.format(params));
171: m_result.append(CSS_DIFF_CLOSE);
172: }
173: }
174: }
|