public List<TokenHook> compile() throws InvalidOperationException { if (this.compiled) { throw new IllegalStateException("XMLEditableString already compiled"); } if (tokenMask != null) { for (int[] positions : this.tokenMask) { int startPosition = positions[0]; int length = positions[1]; TokenHook hook = new TokenHook(startPosition, length, TokenHook.TokenType.Word); hook.processedString = this.currentString.substring(startPosition, startPosition + length); this.tokens.add(hook); } } this.reverseChangeLog(); this.compiled = true; ArrayList<TokenHook> hooks = new ArrayList<>(this.tokens.size() + this.xml.size()); hooks.addAll(this.tokens); hooks.addAll(this.xml); Collections.sort(hooks, (t1, t2) -> t1.startIndex - t2.startIndex); return hooks; }
protected void applyOperations(Collection<Operation> operations, boolean save) throws InvalidOperationException { if (this.compiled) { throw new IllegalStateException("XMLEditableString already compiled"); } for (Operation operation : operations) { int operationEndIndex = operation.startIndex + operation.length; operation.originalString = this.currentString.substring(operation.startIndex, operationEndIndex); int delta = operation.lengthNewString - operation.length; if (delta != 0) { for (TokenHook hook : this.tokens) { int hookLastEditedIndex = hook.startIndex + hook.length - 1; if (hook.startIndex >= operationEndIndex) { hook.startIndex += delta; } else if (hook.startIndex > operation.startIndex) { throw new InvalidOperationException(operation, hook); } else if (hook.startIndex == operation.startIndex && operation.length > hook.length) { throw new InvalidOperationException(operation, hook); } else if (hook.startIndex == operation.startIndex && operation.length < hook.length) { hook.length += delta; } else if (hook.startIndex == operation.startIndex) { hook.length = operation.lengthNewString; } else if (hookLastEditedIndex >= operationEndIndex) { hook.length += delta; } else if (hookLastEditedIndex >= operation.startIndex) { throw new InvalidOperationException(operation, hook); } else if (hookLastEditedIndex < operation.startIndex) { // Do nothing } else { throw new InvalidOperationException(operation, hook, "Unexpected situation"); } } } if (TokenHook.TokenType.XML.equals(operation.tokenType)) { for (TokenHook hook : this.xml) { int hookLastEditedIndex = hook.startIndex + hook.length - 1; if (hook.startIndex >= operationEndIndex) { hook.startIndex += delta; } else if (hook.startIndex > operation.startIndex) { throw new InvalidOperationException(operation, hook); } else if (hook.startIndex == operation.startIndex && operation.length > hook.length) { throw new InvalidOperationException(operation, hook); } else if (hook.startIndex == operation.startIndex && operation.length < hook.length) { hook.length += delta; } else if (hook.startIndex == operation.startIndex) { hook.length = operation.lengthNewString; } else if (hookLastEditedIndex >= operationEndIndex) { hook.length += delta; } else if (hookLastEditedIndex >= operation.startIndex) { throw new InvalidOperationException(operation, hook); } else if (hookLastEditedIndex < operation.startIndex) { // Do nothing } else { throw new InvalidOperationException(operation, hook, "Unexpected situation"); } } } if (!TokenHook.TokenType.Word.equals(operation.tokenType)) { this.currentString.replace(operation.startIndex, operationEndIndex, operation.newString); } if (save) { if (operation.tokenType != null) { if (TokenHook.TokenType.XML.equals(operation.tokenType)) { TokenHook hook = new TokenHook(operation.startIndex, operation.lengthNewString, operation.tokenType); this.xml.add(hook); } else { if (this.tokenMask == null) { this.tokenMask = new TokenMask(this.currentString.length()); } this.tokenMask.setToken(operation.startIndex, operation.lengthNewString); } } this.changeLog.push(operation); } } }