/* * Copyright 2000-2009 JetBrains s.r.o. * * 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 com.intellij.openapi.editor.impl; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.util.diff.FilesTooBigForDiffException; /** * This class is an extension to range marker that tries to restore its range even in situations when target text referenced by it * is replaced. * <p/> * Example: consider that the user selects all text at editor (Ctrl+A), copies it to the buffer (Ctrl+C) and performs paste (Ctrl+V). * All document text is replaced then but in essence it's the same, hence, we may want particular range markers to be still valid. * * @author max */ class PersistentRangeMarker extends RangeMarkerImpl { private int myStartLine; private int myStartColumn; private int myEndLine; private int myEndColumn; PersistentRangeMarker(DocumentEx document, int startOffset, int endOffset, boolean register) { super(document, startOffset, endOffset, register); storeLinesAndCols(null); } private void storeLinesAndCols(DocumentEvent e) { // document might have been changed already int startOffset = getStartOffset(); if (startOffset <= myDocument.getTextLength()) { myStartLine = myDocument.getLineNumber(startOffset); myStartColumn = startOffset - myDocument.getLineStartOffset(myStartLine); if (myStartColumn < 0) { invalidate(e); } } else { invalidate(e); } int endOffset = getEndOffset(); if (endOffset <= myDocument.getTextLength()) { myEndLine = myDocument.getLineNumber(endOffset); myEndColumn = endOffset - myDocument.getLineStartOffset(myEndLine); if (myEndColumn < 0) { invalidate(e); } } else { invalidate(e); } } private boolean translateViaDiff(final DocumentEventImpl event) { try { myStartLine = event.translateLineViaDiffStrict(myStartLine); DocumentEx document = getDocument(); if (myStartLine < 0 || myStartLine >= document.getLineCount()) { invalidate(event); } else { int start = document.getLineStartOffset(myStartLine) + myStartColumn; if (start >= document.getTextLength()) return false; setIntervalStart(start); } myEndLine = event.translateLineViaDiffStrict(myEndLine); if (myEndLine < 0 || myEndLine >= document.getLineCount()) { invalidate(event); } else { int end = document.getLineStartOffset(myEndLine) + myEndColumn; if (end > document.getTextLength()) return false; setIntervalEnd(end); } return true; } catch (FilesTooBigForDiffException e) { return false; } } @Override protected void changedUpdateImpl(DocumentEvent e) { DocumentEventImpl event = (DocumentEventImpl)e; final boolean shouldTranslateViaDiff = PersistentRangeMarkerUtil.shouldTranslateViaDiff(event, this); boolean wasTranslated = shouldTranslateViaDiff; if (shouldTranslateViaDiff) { wasTranslated = translateViaDiff(event); } if (!wasTranslated) { super.changedUpdateImpl(e); if (isValid()) { storeLinesAndCols(e); } } if (intervalEnd() < intervalStart() || intervalEnd() > getDocument().getTextLength() || myEndLine < myStartLine || myStartLine == myEndLine && myEndColumn < myStartColumn || getDocument().getLineCount() < myEndLine) { invalidate(e); } } @Override public String toString() { return "PersistentRangeMarker" + (isGreedyToLeft() ? "[" : "(") + (isValid() ? "valid" : "invalid") + "," + getStartOffset() + "," + getEndOffset() + " " + myStartLine + ":" + myStartColumn + "-" + myEndLine + ":" + myEndColumn + (isGreedyToRight() ? "]" : ")"); } }