blob: 17dd75359357969c5ef0e6c0b35da8a1b1e8ad48 [file] [log] [blame]
/*
* Copyright 2000-2014 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.softwrap.mapping;
import com.intellij.openapi.editor.impl.VisualSizeChangeListener;
import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType;
import com.intellij.openapi.editor.impl.softwrap.SoftWrapPainter;
import gnu.trove.TIntIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.ArrayList;
import java.util.List;
/**
* Wraps soft-wraps specific document parsing to the {@link VisualSizeChangeListener} API.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 12/6/10 12:02 PM
*/
public class SoftWrapAwareVisualSizeManager extends SoftWrapAwareDocumentParsingListenerAdapter {
private final List<VisualSizeChangeListener> myListeners = new ArrayList<VisualSizeChangeListener>();
private final TIntIntHashMap myLineWidths = new TIntIntHashMap();
private SoftWrapPainter myPainter;
/**
* There is a possible case that particular recalculation finished abruptly
* (see {@link #onRecalculationEnd(IncrementalCacheUpdateEvent, boolean)}). We need to know last processed logical line
* then in order to correctly notify the listeners.
*/
private int myLastLogicalLine;
public SoftWrapAwareVisualSizeManager(@NotNull SoftWrapPainter painter) {
myPainter = painter;
}
public boolean addVisualSizeChangeListener(@NotNull VisualSizeChangeListener listener) {
return myListeners.add(listener);
}
@Override
public void onCacheUpdateStart(@NotNull IncrementalCacheUpdateEvent event) {
myLineWidths.clear();
}
@Override
public void onRecalculationEnd(@NotNull IncrementalCacheUpdateEvent event, boolean normal) {
if (myListeners.isEmpty()) {
return;
}
int startLine = event.getStartLogicalLine();
int oldEndLine = event.getOldEndLogicalLine();
for (VisualSizeChangeListener listener : myListeners) {
listener.onLineWidthsChange(startLine, oldEndLine, myLastLogicalLine, myLineWidths);
}
}
@Override
public void onVisualLineEnd(@NotNull EditorPosition position) {
if (myListeners.isEmpty()) {
return;
}
updateLineWidthIfNecessary(position.logicalLine, position.x);
myLastLogicalLine = position.logicalLine;
}
@Override
public void beforeSoftWrapLineFeed(@NotNull EditorPosition position) {
int newWidth = position.x + myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
myLastLogicalLine = position.logicalLine;
if (!myLineWidths.contains(position.logicalLine)) {
myLineWidths.put(position.logicalLine, newWidth);
return;
}
updateLineWidthIfNecessary(position.logicalLine, newWidth);
}
private void updateLineWidthIfNecessary(int line, int width) {
int storedWidth = myLineWidths.get(line);
if (width > storedWidth) {
myLineWidths.put(line, width);
}
}
@TestOnly
public void setSoftWrapPainter(SoftWrapPainter painter) {
myPainter = painter;
}
}