/** * Copyright 2009 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.model.document.util; import org.waveprotocol.wave.model.document.AnnotationCursor; import org.waveprotocol.wave.model.document.AnnotationInterval; import org.waveprotocol.wave.model.document.MutableAnnotationSet; import org.waveprotocol.wave.model.document.RangedAnnotation; import org.waveprotocol.wave.model.document.indexed.RawAnnotationSet; import org.waveprotocol.wave.model.util.Preconditions; import org.waveprotocol.wave.model.util.ReadableStringMap; import org.waveprotocol.wave.model.util.ReadableStringSet; import java.util.List; /** * Presents a mutable view over a raw annotation set that permits object values, * does not emit operations, and enforces that the keys use the local annotation * prefix to avoid mutating the persistent view of annotations. * * @author danilatos@google.com (Daniel Danilatos) */ public class LocalAnnotationSetImpl implements MutableAnnotationSet.Local { /***/ protected final RawAnnotationSet<Object> fullAnnotationSet; /** * @param fullAnnotationSet substrate */ public LocalAnnotationSetImpl(RawAnnotationSet<Object> fullAnnotationSet) { this.fullAnnotationSet = fullAnnotationSet; } /** * Checks that the given key is a valid local key - does nothing if it is * @param key key to check * @throws IllegalArgumentException if the key is not valid */ protected final void checkLocalKey(String key) { if (!Annotations.isLocal(key)) { throw new IllegalArgumentException("Not a local annotation key: " + key); } } @Override public void setAnnotation(int start, int end, String key, Object value) { Preconditions.checkPositionIndexes(start, end, fullAnnotationSet.size()); checkLocalKey(key); if (end - start > 0) { fullAnnotationSet.begin(); if (start > 0) { fullAnnotationSet.skip(start); } fullAnnotationSet.startAnnotation(key, value); if (end - start > 0) { fullAnnotationSet.skip(end - start); } fullAnnotationSet.endAnnotation(key); fullAnnotationSet.finish(); } } @Override public void resetAnnotation(int start, int end, String key, Object value) { Preconditions.checkPositionIndexes(start, end, fullAnnotationSet.size()); checkLocalKey(key); if (end - start > 0) { fullAnnotationSet.begin(); fullAnnotationSet.startAnnotation(key, null); if (start > 0) { fullAnnotationSet.skip(start); } fullAnnotationSet.startAnnotation(key, value); fullAnnotationSet.skip(end - start); fullAnnotationSet.startAnnotation(key, null); if (size() - end > 0) { fullAnnotationSet.skip(size() - end); } fullAnnotationSet.endAnnotation(key); fullAnnotationSet.finish(); } } @Override @Deprecated public void resetAnnotationsInRange(int rangeStart, int rangeEnd, String key, List<RangedValue<Object>> values) { throw new RuntimeException("This method is a server side hack only"); } @Override public Object getAnnotation(int start, String key) { return fullAnnotationSet.getAnnotation(start, key); } @Override public int firstAnnotationChange(int start, int end, String key, Object fromValue) { return fullAnnotationSet.firstAnnotationChange(start, end, key, fromValue); } @Override public int lastAnnotationChange(int start, int end, String key, Object fromValue) { return fullAnnotationSet.lastAnnotationChange(start, end, key, fromValue); } @Override public int size() { return fullAnnotationSet.size(); } @Override public AnnotationCursor annotationCursor(int start, int end, ReadableStringSet keys) { return new GenericAnnotationCursor<Object>(this, start, end, keys); } @Override public Iterable<AnnotationInterval<Object>> annotationIntervals(int start, int end, ReadableStringSet keys) { return fullAnnotationSet.annotationIntervals(start, end, keys); } @Override public Iterable<RangedAnnotation<Object>> rangedAnnotations(int start, int end, ReadableStringSet keys) { return fullAnnotationSet.rangedAnnotations(start, end, keys); } @Override public void forEachAnnotationAt(int location, ReadableStringMap.ProcV<Object> callback) { throw new RuntimeException("not implemented"); } @Override public ReadableStringSet knownKeys() { return fullAnnotationSet.knownKeys(); } }