/**
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.client.editor.impl;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.StyleInjector;
import org.waveprotocol.wave.client.editor.content.TransparentManager;
import org.waveprotocol.wave.model.document.util.FilteredView.Skip;
import java.util.ArrayList;
import java.util.List;
/**
* Transparent node manager for diff annotations
* Keeps track of all diff annotation nodes for a given document
*
* @author danilatos@google.com (Daniel Danilatos)
*/
public class DiffManager implements TransparentManager<Element> {
private static final DiffManagerResources resources = GWT.create(DiffManagerResources.class);
static {
StyleInjector.inject(resources.css().getText(), true);
}
private static final String DIFF_KEY = NodeManager.getNextMarkerName("dt");
/**
* Type of diff annotation
*/
public enum DiffType {
/** insert/insertxml op */
INSERT,
/** delete op */
DELETE,
}
/**
* Annotation element we're keeping track of
*/
private final List<Element> elements = new ArrayList<Element>();
/**
* @param element
* @return The annotation type of the given element, or null if it is not
* an element managed by this instance
*/
public DiffType getDiffType(Element element) {
return element == null || NodeManager.getTransparentManager(element) != this
? null : (DiffType) element.getPropertyObject(DIFF_KEY);
}
/**
* Create a diff annotation element
* @param type The type of change it will be annotating
* @return The newly created element
*/
public Element createElement(DiffType type) {
SpanElement element = Document.get().createSpanElement();
element.setPropertyObject(DIFF_KEY, type);
NodeManager.setTransparentBackref(element, this);
// HACK(danilatos): Demo looms, no time for learning how to use resource bundle etc.
// or adding accessors to stylebase
switch (type) {
case INSERT:
NodeManager.setTransparency(element, Skip.SHALLOW);
break;
case DELETE:
NodeManager.setTransparency(element, Skip.DEEP);
break;
}
styleElement(element, type);
elements.add(element);
return element;
}
/**
* Apply styles and other rendering properties to an element to make it look
* and behave like a diff marker, without actually registering it as such.
*
* @param element
* @param type
*/
public static void styleElement(Element element, DiffType type) {
switch (type) {
case INSERT:
element.addClassName(resources.css().insert());
break;
case DELETE:
element.addClassName(resources.css().delete());
NodeManager.setTransparency(element, Skip.DEEP);
element.setAttribute("contentEditable", "false");
break;
}
}
/**
* Clear diffs from the document
*/
public void clear() {
TransparencyUtil.clear(elements);
}
/**
* Clear diffs from a document that is being discarded
* (All it does is clean up backreferences to assist garbage collection)
*/
public void clearFast() {
for (Element e : elements) {
// Break circular references in browsers with poor gc
e.setPropertyObject(DIFF_KEY, null);
}
elements.clear();
}
/**
* {@inheritDoc}
*/
public Element needToSplit(Element transparentNode) {
DiffType type = (DiffType) transparentNode.getPropertyObject(DIFF_KEY);
if (type == null) {
throw new IllegalArgumentException("No diff type known for given node");
}
return createElement(type);
}
}