2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.lib.editor.view;
44
import java.util.ArrayList;
45
import java.util.List;
46
import javax.swing.text.View;
47
import org.netbeans.editor.view.spi.ViewLayoutState;
50
* Implementation of children for {@link GapLineView}.
54
* @author Miloslav Metelka
58
class GapLineViewChildren extends GapBoxViewChildren {
61
* Value of maximal preferred ascent along the minor axis.
63
private float maxMinorAxisPrefAscent; // 52
66
* Index of the child wrapping the view that has a maximal descent
67
* along the minor axis among all the children.
69
private int maxMinorAxisPrefDescentChildIndex = -1; // 56
72
* Value of maximal preferred descent along the minor axis.
74
private float maxMinorAxisPrefDescent; // 60
77
/** List of rows that is non-null in case the line has to be wrapped */
78
private RowList rowList; // 64
81
GapLineViewChildren(GapBoxView view) {
86
* Compute layout information of the children along the minor axis.
87
* This implementation does wrapped-line layout
89
public void minorAxisLayout() {
90
// Find child states with maximal prefered and minimum spans
91
// along the minor axis
93
int childCount = getChildCount();
94
int maxMinorPrefAscentIndex = -1;
95
int maxMinorPrefDescentIndex = -1;
96
float maxMinorPrefAscentValue = 0f;
97
float maxMinorPrefDescentValue = 0f;
99
for (int i = 0; i < childCount; i++) {
100
ViewLayoutState child = getChild(i);
101
float span = child.getLayoutMinorAxisPreferredSpan();
102
float alignment = child.getLayoutMinorAxisAlignment();
103
float ascent = span * alignment;
104
float descent = span - ascent;
106
if (ascent > maxMinorPrefAscentValue) {
107
maxMinorPrefAscentIndex = i;
108
maxMinorPrefAscentValue = ascent;
111
if (descent > maxMinorPrefDescentValue) {
112
maxMinorPrefDescentIndex = i;
113
maxMinorPrefDescentValue = descent;
118
float maxMinorPrefSpanValue = maxMinorPrefAscentValue + maxMinorPrefDescentValue;
119
setMinorAxisPreferredSpan(maxMinorPrefSpanValue);
120
setMaxMinorAxisPrefAscent(maxMinorPrefAscentValue);
121
setMaxMinorAxisPrefDescent(maxMinorPrefDescentValue);
122
setMaxMinorAxisPrefAscentChildIndex(maxMinorPrefAscentIndex);
123
setMaxMinorAxisPrefDescentChildIndex(maxMinorPrefDescentIndex);
126
private float getPrefAscent(ViewLayoutState child) {
127
float span = child.getLayoutMinorAxisPreferredSpan();
128
float alignment = child.getLayoutMinorAxisAlignment();
129
return span * alignment;
132
private float getMaxMinorAxisPrefAscent() {
133
return maxMinorAxisPrefAscent;
136
private void setMaxMinorAxisPrefAscent(float maxMinorAxisPrefAscent) {
137
this.maxMinorAxisPrefAscent = maxMinorAxisPrefAscent;
140
private int getMaxMinorAxisPrefAscentChildIndex() {
141
// reuse variable for preferred span
142
return super.getMaxMinorAxisPreferredSpanChildIndex();
145
private void setMaxMinorAxisPrefAscentChildIndex(int maxMinorAxisPrefAscentChildIndex) {
146
// reuse variable for preferred span
147
super.setMaxMinorAxisPreferredSpanChildIndex(maxMinorAxisPrefAscentChildIndex);
150
private float getPrefDescent(ViewLayoutState child) {
151
float span = child.getLayoutMinorAxisPreferredSpan();
152
float alignment = child.getLayoutMinorAxisAlignment();
153
return span * (1 - alignment);
156
private float getMaxMinorAxisPrefDescent() {
157
return maxMinorAxisPrefDescent;
160
private void setMaxMinorAxisPrefDescent(float maxMinorAxisPrefDescent) {
161
this.maxMinorAxisPrefDescent = maxMinorAxisPrefDescent;
164
private int getMaxMinorAxisPrefDescentChildIndex() {
165
return maxMinorAxisPrefDescentChildIndex;
168
private void setMaxMinorAxisPrefDescentChildIndex(int maxMinorAxisPrefDescentChildIndex) {
169
this.maxMinorAxisPrefDescentChildIndex = maxMinorAxisPrefDescentChildIndex;
172
int getMaxMinorAxisPrefSpanChildIndex() {
173
throw new IllegalStateException("Should never be called"); // NOI18N
176
void setMaxMinorAxisPrefSpanChildIndex(int maxMinorAxisPrefSpanChildIndex) {
177
throw new IllegalStateException("Should never be called"); // NOI18N
180
protected void replaceUpdateIndexes(int index, int removeLength, int insertLength,
181
int neighborIndex, int neighborIndexAfterReplace, ViewLayoutState neighbor) {
183
boolean minorAxisChanged = false;
184
int endRemoveIndex = index + removeLength;
185
/* Check whether any of the removed children
186
* are either maxPref, maxMin.
187
* If so replace them by the neighbor where appropriate.
188
* Set parent of each remove child to null.
190
/* int ind = getMaxMinorAxisPrefSpanChildIndex();
191
if (ind >= endRemoveIndex) { // must update by diff
192
setMaxMinorAxisPrefSpanChildIndex(ind + insertLength - removeLength);
193
} else if (ind >= index) { // in removed area -> need to change to neighbor
194
if (neighbor == null || neighbor.getLayoutMinorAxisPreferredSpan()
195
< view.getMinorAxisPreferredSpan()
197
minorAxisChanged = true; // minor axis spans must be recomputed
199
setMaxMinorAxisPrefSpanChildIndex(neighborIndexAfterReplace);
204
int ind = getMaxMinorAxisPrefAscentChildIndex();
205
if (ind >= endRemoveIndex) {
206
setMaxMinorAxisPrefAscentChildIndex(ind + insertLength - removeLength);
207
} else if (ind >= index) {
208
float neighborAscent = getPrefAscent(neighbor);
209
if (neighbor == null || neighborAscent < getMaxMinorAxisPrefAscent()) {
210
minorAxisChanged = true;
212
setMaxMinorAxisPrefAscentChildIndex(neighborIndexAfterReplace);
215
ind = getMaxMinorAxisPrefDescentChildIndex();
216
if (ind >= endRemoveIndex) {
217
setMaxMinorAxisPrefDescentChildIndex(ind + insertLength - removeLength);
218
} else if (ind >= index) {
219
float neighborDescent = getPrefDescent(neighbor);
220
if (neighbor == null || neighborDescent < getMaxMinorAxisPrefDescent()) {
221
minorAxisChanged = true;
223
setMaxMinorAxisPrefDescentChildIndex(neighborIndexAfterReplace);
226
if (minorAxisChanged) {
227
view.markMinorAxisPreferenceChanged();
231
protected void minorAxisPreferenceChanged(ViewLayoutState child, int childIndex) {
232
boolean minorAxisChanged = false;
234
float span = child.getLayoutMinorAxisPreferredSpan();
235
float alignment = child.getLayoutMinorAxisAlignment();
236
float ascent = span * alignment;
237
float descent = span - ascent;
239
if (getMaxMinorAxisPrefAscentChildIndex() == -1
240
|| ascent > getMaxMinorAxisPrefAscent()
242
setMaxMinorAxisPrefAscent(ascent);
243
setMaxMinorAxisPrefAscentChildIndex(childIndex);
244
minorAxisChanged = true;
247
if (getMaxMinorAxisPrefDescentChildIndex() == -1
248
|| descent > getMaxMinorAxisPrefDescent()
250
setMaxMinorAxisPrefDescent(descent);
251
setMaxMinorAxisPrefDescentChildIndex(childIndex);
252
minorAxisChanged = true;
256
if (minorAxisChanged) {
257
setMinorAxisPreferredSpan(getMaxMinorAxisPrefAscent()
258
+ getMaxMinorAxisPrefDescent());
260
view.markMinorAxisPreferenceChanged();
264
public float getChildMinorAxisOffset(int childIndex) {
265
ViewLayoutState child = getChild(childIndex);
266
float minorAxisSpan = view.getMinorAxisAssignedSpan();
267
float childMinorMaxSpan = child.getLayoutMinorAxisMaximumSpan();
268
if (childMinorMaxSpan < minorAxisSpan) {
269
// can't make the child to fill the whole span, so align it
270
float align = child.getLayoutMinorAxisAlignment();
271
// Use baseline layout
272
float baseline = getMaxMinorAxisPrefAscent();
273
float span = child.getLayoutMinorAxisPreferredSpan();
274
float alignment = child.getLayoutMinorAxisAlignment();
275
float ascent = span * alignment;
276
return baseline - ascent;
282
private int getRowCount() {
283
return (rowList != null) ? rowList.size() : 0;
286
private Row getRow(int rowIndex) {
287
return (Row)rowList.get(rowIndex);
291
* Return row index that corresponds to the child index.
293
* Search in valid rows only.
294
* @return >=0 and <<code>lastValidRowIndex</code>
295
* or <code>lastValidRowIndex + 1</code> in case the searched
296
* child is above the valid area.
298
private int getRowIndex(int childIndex) {
301
/* can only search up to last valid row index
302
* because the indexes of invalid lines have unpredictable values
303
* which could confuse the binary search
304
* and in worst case make infinite loop.
306
int high = rowList.lastValidRowIndex;
308
while (low <= high) {
309
int mid = (low + high) / 2;
310
Row midRow = getRow(mid);
312
if (midRow.endChildIndex <= childIndex) { // above the mid row
314
} else if (midRow.startChildIndex > childIndex) { // below the mid row
317
// child index inside the row
322
return low; // will be lastValidRowIndex
326
* Data of one visual row when line-wrapping is used.
329
* The views that have to be split are logically included
330
* into the row where they start.
335
* Index of the first child that starts
336
* on this row. If the whole row is covered
337
* with Possible presence of fragment
338
* of the view starting at previous row stored
339
* in <code>rowStartFragment</code> has no effect on this value.
344
* Index of the last child included fully or partly included on this row.
345
* In case the view has to be split
350
* If there is a part of the view starting at one of the previous lines
351
* continuing to this line then this is absolute offset along major axis
352
* at which the part at the begining
353
* of this line starts with.
355
float beforeStartChildMajorOffset;
358
* Layout offset along the minor axis at which this row
361
float minorAxisOffset;
364
* Span of this row along the minor axis.
370
class RowList extends ArrayList {
372
int lastValidRowIndex;