some more assertions
[idea/community.git] / platform / core-impl / src / com / intellij / openapi / editor / impl / event / DocumentEventImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.editor.impl.event;
17
18 import com.intellij.openapi.editor.Document;
19 import com.intellij.openapi.editor.event.DocumentEvent;
20 import com.intellij.util.diff.Diff;
21 import com.intellij.util.diff.FilesTooBigForDiffException;
22 import org.jetbrains.annotations.NotNull;
23
24 public class DocumentEventImpl extends DocumentEvent {
25   private final int myOffset;
26   private final CharSequence myOldString;
27   private final int myOldLength;
28   private final CharSequence myNewString;
29   private final int myNewLength;
30
31   private final long myOldTimeStamp;
32   private final boolean myIsWholeDocReplaced;
33   private Diff.Change myChange;
34   private static final Diff.Change TOO_BIG_FILE = new Diff.Change(0, 0, 0, 0, null);
35
36   private final int myInitialStartOffset;
37   private final int myInitialOldLength;
38
39   public DocumentEventImpl(@NotNull Document document,
40                            int offset,
41                            @NotNull CharSequence oldString,
42                            @NotNull CharSequence newString,
43                            long oldTimeStamp,
44                            boolean wholeTextReplaced) {
45     this(document, offset, oldString, newString, oldTimeStamp, wholeTextReplaced, offset, oldString.length());
46   }
47   public DocumentEventImpl(@NotNull Document document,
48                            int offset,
49                            @NotNull CharSequence oldString,
50                            @NotNull CharSequence newString,
51                            long oldTimeStamp,
52                            boolean wholeTextReplaced,
53                            int initialStartOffset,
54                            int initialOldLength) {
55     super(document);
56     myOffset = offset;
57
58     myOldString = oldString;
59     myOldLength = oldString.length();
60
61     myNewString = newString;
62     myNewLength = newString.length();
63
64     myInitialStartOffset = initialStartOffset;
65     myInitialOldLength = initialOldLength;
66
67     myOldTimeStamp = oldTimeStamp;
68
69     myIsWholeDocReplaced = getDocument().getTextLength() != 0 && wholeTextReplaced;
70     assert initialStartOffset >= 0 : initialStartOffset;
71     assert initialOldLength >= 0 : initialOldLength;
72     assert initialStartOffset+initialOldLength <= document.getTextLength() : "initialStartOffset = " + initialStartOffset + "; initialOldLength = " + initialOldLength+";document.getTextLength() = " + document.getTextLength();
73   }
74
75   @Override
76   public int getOffset() {
77     return myOffset;
78   }
79
80   @Override
81   public int getOldLength() {
82     return myOldLength;
83   }
84
85   @Override
86   public int getNewLength() {
87     return myNewLength;
88   }
89
90   @NotNull
91   @Override
92   public CharSequence getOldFragment() {
93     return myOldString;
94   }
95
96   @NotNull
97   @Override
98   public CharSequence getNewFragment() {
99     return myNewString;
100   }
101
102   @Override
103   @NotNull
104   public Document getDocument() {
105     return (Document)getSource();
106   }
107
108   /**
109    * @return initial start offset as requested in {@link Document#replaceString(int, int, CharSequence)} call, before common prefix and
110    * suffix were removed from the changed range.
111    */
112   public int getInitialStartOffset() {
113     return myInitialStartOffset;
114   }
115
116   /**
117    * @return initial "old fragment" length (endOffset - startOffset) as requested in {@link Document#replaceString(int, int, CharSequence)} call, before common prefix and
118    * suffix were removed from the changed range.
119    */
120   public int getInitialOldLength() {
121     return myInitialOldLength;
122   }
123
124   @Override
125   public long getOldTimeStamp() {
126     return myOldTimeStamp;
127   }
128
129   @SuppressWarnings("HardCodedStringLiteral")
130   public String toString() {
131     return "DocumentEventImpl[myOffset=" + myOffset + ", myOldLength=" + myOldLength + ", myNewLength=" + myNewLength +
132            ", myOldString='" + myOldString + "', myNewString='" + myNewString + "']" + (isWholeTextReplaced() ? " Whole." : ".");
133   }
134
135   @Override
136   public boolean isWholeTextReplaced() {
137     return myIsWholeDocReplaced;
138   }
139
140   public int translateLineViaDiff(int line) throws FilesTooBigForDiffException {
141     Diff.Change change = reBuildDiffIfNeeded();
142     if (change == null) return line;
143
144     int startLine = getDocument().getLineNumber(getOffset());
145     line -= startLine;
146     int newLine = line;
147
148     while (change != null) {
149       if (line < change.line0) break;
150       if (line >= change.line0 + change.deleted) {
151         newLine += change.inserted - change.deleted;
152       }
153       else {
154         int delta = Math.min(change.inserted, line - change.line0);
155         newLine = change.line1 + delta;
156         break;
157       }
158
159       change = change.link;
160     }
161
162     return newLine + startLine;
163   }
164
165   public int translateLineViaDiffStrict(int line) throws FilesTooBigForDiffException {
166     Diff.Change change = reBuildDiffIfNeeded();
167     if (change == null) return line;
168     int startLine = getDocument().getLineNumber(getOffset());
169     if (line < startLine) return line;
170     int translatedRelative = Diff.translateLine(change, line - startLine);
171     return translatedRelative < 0 ? -1 : translatedRelative + startLine;
172   }
173
174   // line numbers in Diff.Change are relative to change start
175   private Diff.Change reBuildDiffIfNeeded() throws FilesTooBigForDiffException {
176     if (myChange == TOO_BIG_FILE) throw new FilesTooBigForDiffException(0);
177     if (myChange == null) {
178       try {
179         myChange = Diff.buildChanges(myOldString, myNewString);
180       }
181       catch (FilesTooBigForDiffException e) {
182         myChange = TOO_BIG_FILE;
183         throw e;
184       }
185     }
186     return myChange;
187   }
188
189
190 }