optimization: replace all occurrence is dramatically faster
[fedora-idea.git] / platform-impl / src / com / intellij / openapi / editor / impl / MarkupModelImpl.java
blobe074f75037f1351a19d49b0c961cac0565911e62
1 /*
2 * Created by IntelliJ IDEA.
3 * User: max
4 * Date: Apr 19, 2002
5 * Time: 2:26:19 PM
6 * To change template for new class use
7 * Code Style | Class Templates options (Tools | IDE Options).
8 */
9 package com.intellij.openapi.editor.impl;
11 import com.intellij.openapi.diagnostic.Logger;
12 import com.intellij.openapi.editor.Document;
13 import com.intellij.openapi.editor.ex.MarkupModelEx;
14 import com.intellij.openapi.editor.impl.event.MarkupModelEvent;
15 import com.intellij.openapi.editor.impl.event.MarkupModelListener;
16 import com.intellij.openapi.editor.markup.HighlighterTargetArea;
17 import com.intellij.openapi.editor.markup.RangeHighlighter;
18 import com.intellij.openapi.editor.markup.TextAttributes;
19 import com.intellij.openapi.util.UserDataHolderBase;
20 import com.intellij.openapi.application.ApplicationManager;
21 import org.jetbrains.annotations.NotNull;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
27 public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx {
28 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.MarkupModelImpl");
29 private final DocumentImpl myDocument;
31 private final HighlighterList myHighlighterList;
32 private final Collection<RangeHighlighter> myHighlighters = new ArrayList<RangeHighlighter>();
33 private RangeHighlighter[] myCachedHighlighters;
34 private final List<MarkupModelListener> myListeners = new ArrayList<MarkupModelListener>();
35 private MarkupModelListener[] myCachedListeners;
37 MarkupModelImpl(DocumentImpl document) {
38 myDocument = document;
39 myHighlighterList = new HighlighterList(document) {
40 @Override
41 protected void assertDispatchThread() {
42 MarkupModelImpl.this.assertDispatchThread();
47 protected void assertDispatchThread() {
48 ApplicationManager.getApplication().assertIsDispatchThread();
51 public void dispose() {
52 myHighlighterList.dispose();
55 @NotNull
56 public RangeHighlighter addLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) {
57 if (lineNumber >= getDocument().getLineCount() || lineNumber < 0) {
58 throw new IndexOutOfBoundsException("lineNumber:" + lineNumber + ". Shold be in [0, " + (getDocument().getLineCount() - 1) + "]");
61 int offset = getFirstNonspaceCharOffset(getDocument(), lineNumber);
63 return addRangeHighlighter(offset, offset, layer, textAttributes, HighlighterTargetArea.LINES_IN_RANGE);
66 public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) {
67 if (lineNumber >= getDocument().getLineCount() || lineNumber < 0) return null;
69 int offset = getFirstNonspaceCharOffset(getDocument(), lineNumber);
71 return addRangeHighlighter(offset, offset, layer, textAttributes, HighlighterTargetArea.LINES_IN_RANGE, true);
74 static int getFirstNonspaceCharOffset(Document doc, int lineNumber) {
75 int lineStart = doc.getLineStartOffset(lineNumber);
76 int lineEnd = doc.getLineEndOffset(lineNumber);
77 CharSequence text = doc.getCharsSequence();
78 int offset = lineStart;
79 for (int i = lineStart; i < lineEnd; i++) {
80 char c = text.charAt(i);
81 if (c != ' ' && c != '\t') {
82 offset = i;
83 break;
86 return offset;
89 @NotNull
90 public RangeHighlighter[] getAllHighlighters() {
91 if (myCachedHighlighters == null) {
92 myCachedHighlighters = myHighlighters.toArray(new RangeHighlighter[myHighlighters.size()]);
94 return myCachedHighlighters;
97 private RangeHighlighter addRangeHighlighter(int startOffset,
98 int endOffset,
99 int layer,
100 TextAttributes textAttributes,
101 HighlighterTargetArea targetArea,
102 boolean isPersistent) {
103 RangeHighlighterImpl segmentHighlighter = new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea,
104 textAttributes, isPersistent);
105 myHighlighters.add(segmentHighlighter);
106 myCachedHighlighters = null;
107 myHighlighterList.addSegmentHighlighter(segmentHighlighter);
108 fireSegmentHighlighterChanged(segmentHighlighter);
109 return segmentHighlighter;
113 @NotNull
114 public RangeHighlighter addRangeHighlighter(int startOffset,
115 int endOffset,
116 int layer,
117 TextAttributes textAttributes,
118 @NotNull HighlighterTargetArea targetArea) {
119 return addRangeHighlighter(startOffset, endOffset, layer, textAttributes, targetArea, false);
122 public void removeHighlighter(RangeHighlighter segmentHighlighter) {
123 boolean removed = myHighlighters.remove(segmentHighlighter);
124 LOG.assertTrue(removed);
125 myCachedHighlighters = null;
126 myHighlighterList.removeSegmentHighlighter(segmentHighlighter);
127 fireSegmentHighlighterChanged(segmentHighlighter);
130 public void removeAllHighlighters() {
131 for (RangeHighlighter highlighter : myHighlighters) {
132 fireSegmentHighlighterChanged(highlighter);
133 myHighlighterList.removeSegmentHighlighter(highlighter);
135 myHighlighters.clear();
136 myCachedHighlighters = null;
139 @NotNull
140 public Document getDocument() {
141 return myDocument;
144 public void addMarkupModelListener(MarkupModelListener listener) {
145 myListeners.add(listener);
146 myCachedListeners = null;
149 public void removeMarkupModelListener(MarkupModelListener listener) {
150 boolean success = myListeners.remove(listener);
151 LOG.assertTrue(success);
152 myCachedListeners = null;
155 public void setRangeHighlighterAttributes(final RangeHighlighter highlighter, final TextAttributes textAttributes) {
156 ((RangeHighlighterImpl)highlighter).setTextAttributes(textAttributes);
157 fireSegmentHighlighterChanged(highlighter);
160 private MarkupModelListener[] getCachedListeners() {
161 if (myCachedListeners == null) {
162 myCachedListeners = myListeners.isEmpty() ? MarkupModelListener.EMPTY_ARRAY : myListeners.toArray(new MarkupModelListener[myListeners.size()]);
164 return myCachedListeners;
167 protected void fireSegmentHighlighterChanged(RangeHighlighter segmentHighlighter) {
168 MarkupModelEvent event = new MarkupModelEvent(this, segmentHighlighter);
169 MarkupModelListener[] listeners = getCachedListeners();
170 for (MarkupModelListener listener : listeners) {
171 listener.rangeHighlighterChanged(event);
175 public HighlighterList getHighlighterList() {
176 return myHighlighterList;
179 public boolean containsHighlighter(RangeHighlighter highlighter) {
180 return myHighlighters.contains(highlighter);