001: /*
002: * Copyright 2007 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.diff.html;
017:
018: import org.outerj.daisy.diff.html.dom.ImageNode;
019: import org.outerj.daisy.diff.html.dom.Node;
020: import org.outerj.daisy.diff.html.dom.TagNode;
021: import org.outerj.daisy.diff.html.dom.TextNode;
022: import org.outerj.daisy.diff.html.modification.Modification;
023: import org.outerj.daisy.diff.html.modification.ModificationType;
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.SAXException;
026: import org.xml.sax.helpers.AttributesImpl;
027:
028: /**
029: * Takes a branch root and creates an HTML file for it.
030: */
031: public class HtmlSaxDiffOutput {
032:
033: private ContentHandler handler;
034:
035: private String prefix;
036:
037: public HtmlSaxDiffOutput(ContentHandler handler, String name) {
038: this .handler = handler;
039: this .prefix = name;
040: }
041:
042: public void toHTML(TagNode node) throws SAXException {
043:
044: if (!node.getQName().equalsIgnoreCase("img")
045: && !node.getQName().equalsIgnoreCase("body")) {
046: handler.startElement("", node.getQName(), node.getQName(),
047: node.getAttributes());
048: }
049:
050: boolean newStarted = false;
051: boolean remStarted = false;
052: boolean changeStarted = false;
053: String changeTXT = "";
054:
055: for (Node child : node) {
056: if (child instanceof TagNode) {
057: if (newStarted) {
058: handler.endElement("", "span", "span");
059: newStarted = false;
060: } else if (changeStarted) {
061: handler.endElement("", "span", "span");
062: changeStarted = false;
063: } else if (remStarted) {
064: handler.endElement("", "span", "span");
065: remStarted = false;
066: }
067: toHTML(((TagNode) child));
068: } else if (child instanceof TextNode) {
069: TextNode textChild = (TextNode) child;
070: Modification mod = textChild.getModification();
071:
072: if (newStarted
073: && (mod.getType() != ModificationType.ADDED || mod
074: .isFirstOfID())) {
075: handler.endElement("", "span", "span");
076: newStarted = false;
077: } else if (changeStarted
078: && (mod.getType() != ModificationType.CHANGED
079: || !mod.getChanges().equals(changeTXT) || mod
080: .isFirstOfID())) {
081: handler.endElement("", "span", "span");
082: changeStarted = false;
083: } else if (remStarted
084: && (mod.getType() != ModificationType.REMOVED || mod
085: .isFirstOfID())) {
086: handler.endElement("", "span", "span");
087: remStarted = false;
088: }
089:
090: //no else because a removed part can just be closed and a new part can start
091: if (!newStarted
092: && mod.getType() == ModificationType.ADDED) {
093: AttributesImpl attrs = new AttributesImpl();
094: attrs.addAttribute("", "class", "class", "CDATA",
095: "diff-html-added");
096: if (mod.isFirstOfID()) {
097: attrs.addAttribute("", "id", "id", "CDATA", mod
098: .getType()
099: + "-" + prefix + "-" + mod.getID());
100: }
101:
102: addAttributes(mod, attrs);
103:
104: handler.startElement("", "span", "span", attrs);
105: newStarted = true;
106: } else if (!changeStarted
107: && mod.getType() == ModificationType.CHANGED) {
108: AttributesImpl attrs = new AttributesImpl();
109: attrs.addAttribute("", "class", "class", "CDATA",
110: "diff-html-changed");
111: if (mod.isFirstOfID()) {
112: attrs.addAttribute("", "id", "id", "CDATA", mod
113: .getType()
114: + "-" + prefix + "-" + mod.getID());
115: }
116:
117: addAttributes(mod, attrs);
118: handler.startElement("", "span", "span", attrs);
119:
120: changeStarted = true;
121: changeTXT = mod.getChanges();
122: } else if (!remStarted
123: && mod.getType() == ModificationType.REMOVED) {
124: AttributesImpl attrs = new AttributesImpl();
125: attrs.addAttribute("", "class", "class", "CDATA",
126: "diff-html-removed");
127: if (mod.isFirstOfID()) {
128: attrs.addAttribute("", "id", "id", "CDATA", mod
129: .getType()
130: + "-" + prefix + "-" + mod.getID());
131: }
132: addAttributes(mod, attrs);
133:
134: handler.startElement("", "span", "span", attrs);
135: remStarted = true;
136: }
137:
138: char[] chars = textChild.getText().toCharArray();
139:
140: if (textChild instanceof ImageNode) {
141: writeImage(textChild);
142: } else {
143: handler.characters(chars, 0, chars.length);
144: }
145:
146: }
147: }
148:
149: if (newStarted) {
150: handler.endElement("", "span", "span");
151: newStarted = false;
152: } else if (changeStarted) {
153: handler.endElement("", "span", "span");
154: changeStarted = false;
155: } else if (remStarted) {
156: handler.endElement("", "span", "span");
157: remStarted = false;
158: }
159:
160: if (!node.getQName().equalsIgnoreCase("img")
161: && !node.getQName().equalsIgnoreCase("body"))
162: handler.endElement("", node.getQName(), node.getQName());
163:
164: }
165:
166: private void writeImage(TextNode textChild) throws SAXException {
167: ImageNode imgNode = (ImageNode) textChild;
168: AttributesImpl attrs = imgNode.getAttributes();
169: if (imgNode.getModification().getType() == ModificationType.REMOVED)
170: attrs.addAttribute("", "changeType", "changeType", "CDATA",
171: "diff-removed-image");
172: else if (imgNode.getModification().getType() == ModificationType.ADDED)
173: attrs.addAttribute("", "changeType", "changeType", "CDATA",
174: "diff-added-image");
175: handler.startElement("", "img", "img", attrs);
176: handler.endElement("", "img", "img");
177: }
178:
179: private void addAttributes(Modification mod, AttributesImpl attrs) {
180:
181: if (mod.getType() == ModificationType.CHANGED) {
182: String changes = mod.getChanges();
183: attrs.addAttribute("", "changes", "changes", "CDATA",
184: changes);
185: }
186:
187: String previous;
188: if (mod.getPrevious() == null) {
189: previous = "first-" + prefix;
190: } else {
191: previous = mod.getPrevious().getType() + "-" + prefix + "-"
192: + mod.getPrevious().getID();
193: }
194: attrs.addAttribute("", "previous", "previous", "CDATA",
195: previous);
196:
197: String changeId = mod.getType() + "-" + prefix + "-"
198: + mod.getID();
199: attrs.addAttribute("", "changeId", "changeId", "CDATA",
200: changeId);
201:
202: String next;
203: if (mod.getNext() == null) {
204: next = "last-" + prefix;
205: } else {
206: next = mod.getNext().getType() + "-" + prefix + "-"
207: + mod.getNext().getID();
208: }
209: attrs.addAttribute("", "next", "next", "CDATA", next);
210:
211: }
212:
213: }
|