Ticket #2422: text_justification.2.patch
File text_justification.2.patch, 12.4 KB (added by boyanl, 15 years ago) |
---|
-
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/mvc/TextModelLogic.java
### Eclipse Workspace Patch 1.0 #P sophie
107 107 if (clickCount % 3 == 2) { 108 108 Break wordBreak = Breaks.WORD_BREAK; 109 109 int endPos = wordBreak.getNextBreakPos(rawText, pos); 110 while (endPos < rawText.getEnd()110 while (endPos <= rawText.getEnd() 111 111 && endPos > rawText.getBegin() 112 112 && CommonChar.getWordSeparators(). 113 113 contains(rawText.unitAt(endPos - 1).getChar())) { … … 745 745 case LINE_END : 746 746 lineEnds = layout.getLineEnds(caret); 747 747 if (lineEnds != null) { 748 result = ImmTextUtils.advance(text, textBegin, lineEnds.getEnd()); 748 int end = lineEnds.getEnd(); 749 while (end > text.getBegin() && end < text.getEnd() && text.unitAt(end).getChar() == CommonChar.PARA_BREAK) { 750 end = ImmTextUtils.advance(text, end, -1); 751 } 752 753 result = ImmTextUtils.advance(text, textBegin, end); 749 754 } 750 755 break; 751 756 -
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/model/TextUtils.java
26 26 */ 27 27 public static int findPrevChar(ImmText text, int startPos, List<Character> chars) { 28 28 int pos = (startPos != -1) ? startPos : text.getBegin(); 29 if (pos != text.getBegin() && pos == text.getEnd()) { 30 --pos; 31 } 29 32 30 33 while (pos > text.getBegin()) { 31 34 if (chars.contains(text.unitAt(pos).getChar())) { … … 56 59 */ 57 60 public static int findNextChar(ImmText text, int startIndex, List<Character> chars) { 58 61 59 assert startIndex >= 0 && startIndex < text.getEnd() : startIndex; 62 assert startIndex >= 0 && startIndex <= text.getEnd() : startIndex; 63 if (startIndex == text.getEnd ()) 64 return startIndex; 60 65 int index = startIndex + 1; 61 66 62 67 while (index < text.getEnd()) { -
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/layout/LayoutUtils.java
58 58 59 59 List<Character> lineBreaks = CommonChar.getEffectiveBreaks(CommonChar.LINE_BREAK); 60 60 int pos = TextUtils.findNextChar(this.areaText, begin, lineBreaks); 61 61 62 62 if (pos == -1 || this.areaText.getEnd() == 0) { 63 63 return null; 64 64 } … … 70 70 pos = nextPos; 71 71 } 72 72 } 73 74 //checks for trailing para break and adds it (if any) 75 int paraBreak = nextPos; 76 if (paraBreak < this.areaText.getEnd() && 77 this.areaText.unitAt(paraBreak).getChar() == CommonChar.PARA_BREAK ) 78 ++paraBreak; 73 79 74 80 assert ImmTextUtils.isIndexInText(pos, this.areaText); 75 81 ImmText res = 76 82 this.areaText.subText(new ImmTextInterval(begin, 77 Math.min( nextPos, this.areaText.getEnd())));83 Math.min(paraBreak, this.areaText.getEnd()))); 78 84 this.areaText = 79 this.areaText.subText(new ImmTextInterval(p os, end));85 this.areaText.subText(new ImmTextInterval(paraBreak, end)); 80 86 81 87 // Empty texts should not be returned. 82 88 if (res.getEnd() == 0) { -
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/layout/LineBreakUtil.java
5 5 6 6 import org.sophie2.base.model.text.elements.Break; 7 7 import org.sophie2.base.model.text.elements.Breaks; 8 import org.sophie2.base.model.text.elements.CommonChar; 8 9 import org.sophie2.base.model.text.model.ImmText; 9 10 import org.sophie2.base.model.text.model.TextRun; 10 11 … … 124 125 * The text to take a word from. 125 126 * @param startIndex 126 127 * The index from which to search the word end. 128 * @param whitespaceBreaks 129 * An list of indices containing all the positions of characters who come after consecutive whitespaces 127 130 * @return 128 131 * A {@link Word} with starting index - startIndex and ending index - the first 129 132 * non-word-breaking character index after the first sequence of white spaces. 130 133 */ 131 static Word get(ImmText text, int startIndex ) {134 static Word get(ImmText text, int startIndex, List<Integer> whitespaceBreaks) { 132 135 133 136 int requiredEnd = getWordEnd(text, startIndex); 134 137 … … 138 141 139 142 assert requiredEnd <= text.getEnd(); 140 143 144 if (whitespaceBreaks != null) { 145 /* 146 * Construct the list of whitespace positions. The actual values in the list are the first characters *after* 147 * whitespaces. Also if the word has trailing whitespaces, the position after the word's end is inserted in the list. 148 */ 149 int ind = start; 150 while (ind < requiredEnd) { 151 char c = text.unitAt(ind).getChar(); 152 if (c == CommonChar.SPACE || 153 c == CommonChar.TAB){ 154 155 while (ind < requiredEnd && 156 (c == CommonChar.SPACE || 157 c == CommonChar.TAB || 158 c == CommonChar.LINE_BREAK)) { 159 c = text.unitAt(ind++).getChar(); 160 } 161 162 whitespaceBreaks.add(ind); 163 } 164 else 165 ++ind; 166 } 167 168 /* 169 * Construct each run between whitespace positions, starting from start 170 */ 171 for (int position : whitespaceBreaks) { 172 while (start < position 173 && (run = TextRun.create(text, start, position)) != null) { 174 runs.add (run); 175 start += run.getRunLength(); 176 } 177 start = position; 178 } 179 } 180 181 //Construct the final run (from the last whitespace position till the end of the word) 141 182 while (start < requiredEnd 142 183 && (run = TextRun.create(text, start, requiredEnd)) != null) { 143 184 runs.add(run); -
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/elements/Breaks.java
36 36 } 37 37 tmpPos += advanceStep; 38 38 } 39 return position;39 return tmpPos; 40 40 } 41 41 }; 42 42 -
modules/org.sophie2.base.model.text/src/main/java/org/sophie2/base/model/text/layout/HotSegmentLayout.java
9 9 import java.awt.geom.Line2D; 10 10 import java.awt.geom.Rectangle2D; 11 11 import java.util.ArrayList; 12 import java.util.Arrays; 12 13 13 14 import org.sophie2.base.commons.util.position.ImmPoint; 14 15 import org.sophie2.base.model.text.elements.CommonAttr; … … 33 34 * Layout with no text. Used to fill spaces that should stay empty. 34 35 */ 35 36 static final HotSegmentLayout EMPTY = 36 new HotSegmentLayout(new ArrayList<TextRun>(), new ArrayList<DoublePoint>(), 0);37 new HotSegmentLayout(new ArrayList<TextRun>(), new ArrayList<DoublePoint>(), new int[0], 0, 0); 37 38 38 39 private final ArrayList<TextRun> textRuns; 39 40 private final ArrayList<DoublePoint> locations; 41 private final int[] wordPos; 40 42 private final double xOffset; 43 private final double textWidth; 41 44 42 45 private HotSegmentLayout( 43 ArrayList<TextRun> runs, ArrayList<DoublePoint> locations, double xOffset) {46 ArrayList<TextRun> runs, ArrayList<DoublePoint> locations, int[] wordPos, double xOffset, double textWidth) { 44 47 45 48 this.textRuns = runs; 46 49 this.locations = locations; 47 50 this.xOffset = xOffset; 51 this.textWidth = textWidth; 52 this.wordPos = wordPos; 48 53 } 49 54 50 55 /** … … 68 73 double remainingWidth = totalWidth; 69 74 ArrayList<TextRun> runs = new ArrayList<TextRun>(); 70 75 ArrayList<DoublePoint> locations = new ArrayList<DoublePoint>(); 76 77 //contains the start indices of whitespace-delimited words (except the first one) 78 ArrayList<Integer> wordPos = new ArrayList<Integer> (); 71 79 72 80 int position = startPos; 73 Word word ;81 Word word = null; 74 82 75 83 // Add as many words as possible. 84 ArrayList<Integer> curWordPos = new ArrayList<Integer> (); 76 85 while (position < text.getEnd() && 77 (word = Word.get(text, position )) != null &&86 (word = Word.get(text, position, curWordPos)) != null && 78 87 word.willFit(totalWidth, remainingWidth) && remainingWidth > 0) { 79 88 80 89 for (TextRun run : word.getRuns()) { … … 98 107 } 99 108 100 109 position += word.getSize(); 110 wordPos.addAll(curWordPos); 111 curWordPos.clear(); 101 112 } 102 113 114 /* 115 * Position contains the first position of a word we were unable to add - either the end of the text (i.e. we added everything), or 116 * some index before it. If we have it in wordPos (i.e. it was the first positions after whitespaces), we have to remove it. 117 */ 118 if (!wordPos.isEmpty () && wordPos.get(wordPos.size() - 1) == position) { 119 wordPos.remove(wordPos.size() - 1); 120 } 121 103 122 // If no words are added, add as many chars as possible. 104 123 if (runs.size() == 0) { 105 124 SophieLog.debug("Could not layout a single word! Will split it to chars!"); … … 113 132 TextRun run = character.getRun(); 114 133 115 134 remainingWidth = addRun(run, baselineOffset, 116 totalWidth, remainingWidth, runs, locations);135 totalWidth, remainingWidth, runs, locations); 117 136 118 137 if (remainingWidth == 0) { 119 138 break; … … 143 162 144 163 TextAlign align = runs.get(0).getAttrValue(CommonAttr.PARA_ALIGNMENT); 145 164 165 int[] arr = new int[wordPos.size()]; 166 for (int i = 0; i < wordPos.size(); ++i) 167 arr[i] = wordPos.get(i) - startPos; 168 146 169 HotSegmentLayout result = 147 new HotSegmentLayout(runs, locations, getAlignOffset(align, remainingWidth));170 new HotSegmentLayout(runs, locations, arr, getAlignOffset(align, remainingWidth), totalWidth - remainingWidth); 148 171 149 if (TextAlign.JUSTIFIED.equals(align)) { 172 //don't justify if the segments end with para/doc break 173 char lastChar = text.unitAt(startPos + result.getConsumedLength() - 1).getChar (); 174 boolean shouldJustify = lastChar != CommonChar.PARA_BREAK && lastChar != CommonChar.DOC_BREAK; 175 if (TextAlign.JUSTIFIED.equals(align) && shouldJustify) { 150 176 return result.getJustifiedLayout(totalWidth); 151 177 } 152 178 … … 391 417 } 392 418 393 419 private HotSegmentLayout getJustifiedLayout(double totalWidth) { 394 // TODO don't know how to do this.. --kyli 395 return this; 420 HotSegmentLayout result; 421 422 /* 423 * Calculate new locations for the runs, based on how much space 424 * we have remaining 425 */ 426 427 ArrayList<DoublePoint> newLocations = new ArrayList<DoublePoint> (this.locations.size()); 428 int pos = 0, placed = 0; 429 430 double remWidth = totalWidth - this.textWidth, averageW = (this.wordPos.length == 0 ? 0 : remWidth / (this.wordPos.length)); 431 //do stuff with locations 432 for (int i = 0; i < this.textRuns.size(); ++i) { 433 434 boolean found = (pos != 0 && Arrays.binarySearch (this.wordPos, pos) >= 0); 435 placed += (found ? 1 : 0); 436 437 DoublePoint element = this.locations.get(i); 438 DoublePoint newElem = new DoublePoint (element.getX() + placed*averageW, element.getY()); 439 newLocations.add(newElem); 440 441 pos += this.textRuns.get(i).getRunLength(); 442 } 443 result = new HotSegmentLayout (this.textRuns, newLocations, this.wordPos, this.xOffset, this.textWidth); 444 445 return result; 396 446 } 397 447 }