@Override public int transformIndex(int index, Operation op, Object param) { if (op instanceof SplitOperation) { SplitOperation s = (SplitOperation) op; index = transformIndex(index, s.getSecond(), param); index = transformIndex(index, s.getFirst(), param); return index; } else if (op instanceof NoOperation) { return index; } else if (op instanceof InsertOperation) { int pos = ((InsertOperation) op).getPosition(); if (index < pos) { return index; } else { return index + ((InsertOperation) op).getTextLength(); } } else if (op instanceof DeleteOperation) { int pos = ((DeleteOperation) op).getPosition(); if (index <= pos) { return index; } else { return index - ((DeleteOperation) op).getTextLength(); } } else { throw new IllegalArgumentException("Unsupported Operation type: " + op); } }
/** * Transform operation <var>op1</var> in the context of another operation <var>op2</var>. The * transformed operation <var>op1'</var> is returned. * * @param op1 the operation to transform * @param op2 the operation which is the context for the other one * @param param a boolean flag to privilege the first operation <code>op1</code> (i.e. remains * unchanged) when two insert operations are equivalent i.e. they have the same position and * origin index. * @return the transformed operation <var>op1'</var> */ @Override public Operation transform(Operation op1, Operation op2, Object param) { log.trace("Transform " + op1 + " in the context of " + op2 + " (privileged==" + param + ")"); boolean privileged = (Boolean) param; /** A NoOperation is not affected. */ if (op1 instanceof NoOperation) { return new NoOperation(); } /** If the context is null, we return op1 unchanged. */ if (op2 instanceof NoOperation) { return op1; } if (op1 instanceof SplitOperation) { /** * Given two operations s1 and s2 to be transformed in the context of op2, we need to * calculate s1' as t(s1, op2) and s2' as t(s2, op2') where op2' is t(op2, s1) <code> * O * s1 / \ op2 * O O * s2 / \ / s1' * O O * \ / s2' * O * </code> */ SplitOperation s = (SplitOperation) op1; return new SplitOperation( transform(s.getFirst(), op2, param), transform(s.getSecond(), transform(op2, s.getFirst(), !privileged), param)); } if (op2 instanceof SplitOperation) { /** * Given an operation op1 to be transformed in the context of two operations s1 and s2, we * need to calculate op1' as t(op1', s2) where op1' is t(op1, s1) <code> * O * s1 / \ op1 * O O * s2 / \ / * O O * op1'\ / * O * </code> */ SplitOperation s = (SplitOperation) op2; return transform(transform(op1, s.getFirst(), param), s.getSecond(), param); } if (op1 instanceof InsertOperation) { if (op2 instanceof InsertOperation) { return transform((InsertOperation) op1, (InsertOperation) op2, privileged); } if (op2 instanceof DeleteOperation) { return transform((InsertOperation) op1, (DeleteOperation) op2); } } if (op1 instanceof DeleteOperation) { if (op2 instanceof InsertOperation) { return transform((DeleteOperation) op1, (InsertOperation) op2); } if (op2 instanceof DeleteOperation) { return transform((DeleteOperation) op1, (DeleteOperation) op2); } } throw new InvalidParameterException("op1: " + op1 + ", op2: " + op2); }