/** * Copyright 2010 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; import org.waveprotocol.wave.model.util.StringMap; public interface AnnotationBehaviour { /** Bias priority for 'container' elements, which bias inwards. */ public static double ELEMENT_PRIORITY = 5.0; /** Bias priority for the default behaviour, placing it behind elements. */ public static double DEFAULT_PRIORITY = 1.0; /** Cursor movements which may affect bias. */ public enum CursorDirection { /** Last movement was to the left. */ FROM_LEFT, /** Last movement was to the right. */ FROM_RIGHT, /** Last movement was unknown or doesn't affect bias. */ NEUTRAL; /** Converts the last cursor movement into a default bias. */ public static BiasDirection toBiasDirection(CursorDirection cursor) { switch (cursor) { case FROM_LEFT: return BiasDirection.LEFT; case FROM_RIGHT: return BiasDirection.RIGHT; } return BiasDirection.NEITHER; } } /** Which 'side' of the gap the cursor is in. */ public enum BiasDirection { /** A) B -- default = assoicated with the previous character */ LEFT, /** A (B -- associated with the next character. */ RIGHT, /** A | B -- right in the middle = unknown. */ NEITHER; } /** Which 'side' of the cursor to inherit the annotation from. */ public enum InheritDirection { /** inherit the annotation from the side the cursor is biassed. */ INSIDE, /** inherit the annotation from the side other side to which the cursor is biassed. */ OUTSIDE, /** do not inherit annotation (null is used instead). */ NEITHER; } /** If required, indicates what type of content is being inserted and may require annotations. */ public enum ContentType { /** normal text, unstyled. */ PLAIN_TEXT, /** rich text with its own stylings. */ RICH_TEXT, } /** * Enumerates the semantic families of annotations. An example usage of this is for * copying a document, deciding what annotations should be brought along. */ public enum AnnotationFamily { /** Part of the core document model - e.g. font colour or links. */ CONTENT, /** Metadata that adds extra information on top of the document - e.g. spell suggestions. */ META, } /** * Shows the priority of this behaviour - behaviours with lower priority value get precedence * in setting the bias direction. */ double getPriority(); /** * Indicates what type of family this behaviour is defined over. */ AnnotationFamily getAnnotationFamily(); /** * Defines the desired bias of the cursor given the current state of annotations. * * @param left Key-Value mappings for annotations to the left of the cursor. * @param right Key-Value mappings for annotations to the right of the cursor. * @param cursor last known value for the cursor movement. * @return Desired bias direction. */ BiasDirection getBias(StringMap<Object> left, StringMap<Object> right, CursorDirection cursor); /** * Defines which side of the cursor to inherit annotations from, given the current state of * annotations and some information about what the annotations are being set over. * Note that in the case of ranged selections being replaced, the cursor is considered to have * the same annotations as the first character of the selected range. * * @param inside Key-Value mappings for annotations inside the cursor. * @param outside Key-Value mappings for annotations outside the cursor. * @param type Type of content being replaced * @return Desired inheritence behaviour. */ InheritDirection replace(StringMap<Object> inside, StringMap<Object> outside, ContentType type); /** * Defines the default model behaviour for annotations - that is, does not specify a bias, * replacement always comes from inside the cursor, and is prioritised behind elements. */ public static class DefaultAnnotationBehaviour implements AnnotationBehaviour { private final AnnotationFamily family; public DefaultAnnotationBehaviour(AnnotationFamily family) { this.family = family; } @Override public BiasDirection getBias(StringMap<Object> left, StringMap<Object> right, CursorDirection cursor) { return BiasDirection.NEITHER; } @Override public double getPriority() { return DEFAULT_PRIORITY; } @Override public InheritDirection replace(StringMap<Object> inside, StringMap<Object> outside, ContentType type) { // Default behaviour: inherit, unless rich text in which case leave formatting as-is return type == ContentType.RICH_TEXT ? InheritDirection.NEITHER : InheritDirection.INSIDE; } @Override public AnnotationFamily getAnnotationFamily() { return family; } } /** * One of the standard meta-data annotation behaviours. This follows DefaultAnnotation * behaviour, except when selection is replaced, this does not inherit the * annotation from either side. */ public static final AnnotationBehaviour REPLACE_NEITHER = new DefaultAnnotationBehaviour(AnnotationFamily.META) { @Override public InheritDirection replace(StringMap<Object> inside, StringMap<Object> outside, ContentType type) { return InheritDirection.NEITHER; } }; }