mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-115374 "Print file" truncates the code on Mac
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.codeEditor.printing;
|
||||
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
|
||||
public class LineWrapper {
|
||||
|
||||
public IntArrayList calcBreakOffsets(char[] text, int startOffset, int endOffset, int column, double x, double clipX, WidthProvider widthProvider) {
|
||||
IntArrayList breakOffsets = new IntArrayList();
|
||||
int nextOffset = startOffset;
|
||||
while (true) {
|
||||
int prevOffset = nextOffset;
|
||||
nextOffset = calcWordBreakOffset(text, nextOffset, endOffset, x, clipX, widthProvider);
|
||||
if (nextOffset == prevOffset && column == 0) {
|
||||
nextOffset = calcCharBreakOffset(text, nextOffset, endOffset, x, clipX, widthProvider);
|
||||
if (nextOffset == prevOffset) {
|
||||
nextOffset++; // extremal case when even one character doesn't fit into clip width
|
||||
}
|
||||
}
|
||||
if (nextOffset >= endOffset) {
|
||||
break;
|
||||
}
|
||||
breakOffsets.add(nextOffset);
|
||||
column = 0;
|
||||
x = 0;
|
||||
}
|
||||
return breakOffsets;
|
||||
}
|
||||
|
||||
private static int calcCharBreakOffset(char[] text, int offset, int endOffset, double x, double clipX, WidthProvider widthProvider) {
|
||||
double newX = x;
|
||||
int breakOffset = offset;
|
||||
while (breakOffset < endOffset) {
|
||||
int nextOffset = breakOffset + 1;
|
||||
newX += widthProvider.getWidth(text, breakOffset, nextOffset - breakOffset, newX);
|
||||
if (newX > clipX) {
|
||||
return breakOffset;
|
||||
}
|
||||
breakOffset = nextOffset;
|
||||
}
|
||||
return breakOffset;
|
||||
}
|
||||
|
||||
private static int calcWordBreakOffset(char[] text, int offset, int endOffset, double x, double clipX, WidthProvider widthProvider) {
|
||||
double newX = x;
|
||||
int breakOffset = offset;
|
||||
while (breakOffset < endOffset) {
|
||||
int nextOffset = getNextWordBreak(text, breakOffset, endOffset);
|
||||
newX += widthProvider.getWidth(text, breakOffset, nextOffset - breakOffset, newX);
|
||||
if (newX > clipX) {
|
||||
return breakOffset;
|
||||
}
|
||||
breakOffset = nextOffset;
|
||||
}
|
||||
return breakOffset;
|
||||
}
|
||||
|
||||
private static int getNextWordBreak(char[] text, int offset, int endOffset) {
|
||||
boolean isId = Character.isJavaIdentifierPart(text[offset]);
|
||||
for (int i = offset + 1; i < endOffset; i++) {
|
||||
if (isId != Character.isJavaIdentifierPart(text[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return endOffset;
|
||||
}
|
||||
|
||||
interface WidthProvider {
|
||||
double getWidth(char[] text, int start, int count, double x);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -68,6 +68,8 @@ class TextPainter extends BasePainter {
|
||||
private final CodeStyleSettings myCodeStyleSettings;
|
||||
private final FileType myFileType;
|
||||
|
||||
private static final LineWrapper ourLineWrapper = new LineWrapper();
|
||||
|
||||
@NonNls private static final String DEFAULT_MEASURE_HEIGHT_TEXT = "A";
|
||||
@NonNls private static final String DEFAULT_MEASURE_WIDTH_TEXT = "w";
|
||||
@NonNls private static final String HEADER_TOKEN_PAGE = "PAGE";
|
||||
@@ -485,20 +487,26 @@ class TextPainter extends BasePainter {
|
||||
return drawTabbedString(g, text, end - myOffset, position, clip, colNumber, backColor, underscoredColor);
|
||||
}
|
||||
|
||||
private boolean drawTabbedString(Graphics2D g, char[] text, int length, Point2D position, Rectangle2D clip,
|
||||
private boolean drawTabbedString(final Graphics2D g, char[] text, int length, Point2D position, Rectangle2D clip,
|
||||
int colNumber, Color backColor, Color underscoredColor) {
|
||||
boolean ret = true;
|
||||
if (myOffset + length >= mySegmentEnd) {
|
||||
ret = false;
|
||||
length = mySegmentEnd - myOffset;
|
||||
}
|
||||
if (length <= 0) { // How it can be?
|
||||
if (length <= 0) { // can happen in recursive invocations below
|
||||
return false;
|
||||
}
|
||||
if (myPrintSettings.WRAP) {
|
||||
double w = getTextSegmentWidth(text, myOffset, length, position.getX(), g);
|
||||
if (position.getX() + w > clip.getWidth()) {
|
||||
IntArrayList breakOffsets = calcBreakOffsets(g, text, myOffset, myOffset + length, colNumber, position, clip);
|
||||
IntArrayList breakOffsets = ourLineWrapper.calcBreakOffsets(text, myOffset, myOffset + length, colNumber, position.getX(),
|
||||
clip.getWidth(), new LineWrapper.WidthProvider() {
|
||||
@Override
|
||||
public double getWidth(char[] text, int start, int count, double x) {
|
||||
return getTextSegmentWidth(text, start, count, x, g);
|
||||
}
|
||||
});
|
||||
int startOffset = myOffset;
|
||||
for (int i = 0; i < breakOffsets.size(); i++) {
|
||||
int breakOffset = breakOffsets.get(i);
|
||||
@@ -508,10 +516,7 @@ class TextPainter extends BasePainter {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (myOffset > startOffset) {
|
||||
drawTabbedString(g, text, startOffset + length - myOffset, position, clip, colNumber, backColor,
|
||||
underscoredColor);
|
||||
}
|
||||
drawTabbedString(g, text, startOffset + length - myOffset, position, clip, colNumber, backColor, underscoredColor);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -572,69 +577,6 @@ class TextPainter extends BasePainter {
|
||||
return v.getLogicalBounds().getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
private IntArrayList calcBreakOffsets(Graphics2D g, char[] text, int offset, int endOffset, int colNumber,
|
||||
Point2D position, Rectangle2D clip) {
|
||||
IntArrayList breakOffsets = new IntArrayList();
|
||||
int nextOffset = offset;
|
||||
double x = position.getX();
|
||||
while (true) {
|
||||
int prevOffset = nextOffset;
|
||||
nextOffset = calcWordBreakOffset(g, text, nextOffset, endOffset, x, clip);
|
||||
if (nextOffset == offset || nextOffset == prevOffset && colNumber == 0) {
|
||||
nextOffset = calcCharBreakOffset(g, text, nextOffset, endOffset, x, clip);
|
||||
if (nextOffset == prevOffset) { //it shouldn't be, but if clip.width is <= 1...
|
||||
return breakOffsets;
|
||||
}
|
||||
}
|
||||
if (nextOffset >= endOffset) {
|
||||
break;
|
||||
}
|
||||
breakOffsets.add(nextOffset);
|
||||
colNumber = 0;
|
||||
x = 0;
|
||||
}
|
||||
return breakOffsets;
|
||||
}
|
||||
|
||||
private int calcCharBreakOffset(Graphics2D g, char[] text, int offset, int endOffset, double x, Rectangle2D clip) {
|
||||
double newX = x;
|
||||
int breakOffset = offset;
|
||||
while (breakOffset < endOffset) {
|
||||
int nextOffset = breakOffset + 1;
|
||||
newX += getTextSegmentWidth(text, breakOffset, nextOffset - breakOffset, newX, g);
|
||||
if (newX > clip.getWidth()) {
|
||||
return breakOffset;
|
||||
}
|
||||
breakOffset = nextOffset;
|
||||
}
|
||||
return breakOffset;
|
||||
}
|
||||
|
||||
private int calcWordBreakOffset(Graphics2D g, char[] text, int offset, int endOffset, double x, Rectangle2D clip) {
|
||||
double newX = x;
|
||||
int breakOffset = offset;
|
||||
while (breakOffset < endOffset) {
|
||||
int nextOffset = getNextWordBreak(text, breakOffset, endOffset);
|
||||
newX += getTextSegmentWidth(text, breakOffset, nextOffset - breakOffset, newX, g);
|
||||
if (newX > clip.getWidth()) {
|
||||
return breakOffset;
|
||||
}
|
||||
breakOffset = nextOffset;
|
||||
}
|
||||
return breakOffset;
|
||||
}
|
||||
|
||||
private static int getNextWordBreak(char[] text, int offset, int endOffset) {
|
||||
boolean isId = Character.isJavaIdentifierPart(text[offset]);
|
||||
for (int i = offset + 1; i < endOffset; i++) {
|
||||
if (isId != Character.isJavaIdentifierPart(text[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return endOffset;
|
||||
}
|
||||
|
||||
private double getTextSegmentWidth(char[] text, int offset, int length, double x, Graphics2D g) {
|
||||
int start = offset;
|
||||
double startX = x;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.codeEditor.printing;
|
||||
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class LineWrapperTest {
|
||||
private final LineWrapper myWrapper = new LineWrapper();
|
||||
private final LineWrapper.WidthProvider myWidthProvider = new LineWrapper.WidthProvider() {
|
||||
@Override
|
||||
public double getWidth(char[] text, int start, int count, double x) {
|
||||
return count; // char width of 1 pixel for all characters
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
doTest("", false, 0);
|
||||
doTest("", true, 0);
|
||||
doTest("", false, 1);
|
||||
doTest("", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleChar() {
|
||||
doTest("a", false, 0.5,
|
||||
0);
|
||||
doTest("a", true, 0.5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCharSplit() {
|
||||
doTest("aa", false, 1.5,
|
||||
0, 1);
|
||||
doTest("aa", true, 1.5,
|
||||
1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtreme() {
|
||||
doTest("aa", false, 0.5,
|
||||
0, 1);
|
||||
doTest("aa", true, 0.5,
|
||||
1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWordSplit() {
|
||||
doTest("aa aa aa", false, 3.5,
|
||||
2, 4, 6, 8);
|
||||
doTest("aa aa aa", true, 3.5,
|
||||
2, 4, 6, 8);
|
||||
}
|
||||
|
||||
private void doTest(String text, boolean atLineStart, double clipWidth, int... expectedBreaks) {
|
||||
IntArrayList actualBreaks = myWrapper.calcBreakOffsets(text.toCharArray(), 0, text.length(), atLineStart ? 0 : 1, 0, clipWidth, myWidthProvider);
|
||||
assertArrayEquals(expectedBreaks, actualBreaks.toArray());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user