001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: *
041: * Contributor(s): Ivan Soleimanipour.
042: */
043:
044: /*
045: * "Line.java"
046: * Line.java 1.12 01/07/24
047: */
048:
049: package org.netbeans.lib.terminalemulator;
050:
051: class Line {
052: public int glyph_glyph;
053: public int glyph_rendition; // Background color for the whole line
054: // This is independent of per-character
055: // rendition.
056:
057: private char buf[]; // actual characters
058: private int attr[]; // attributes (allocated on demand)
059:
060: // SHOULD use shorts?
061: private int capacity; // == buf.length == attr.length
062: private int length; // how much of buf and attr is filled
063:
064: public Line() {
065: reset();
066: }
067:
068: public void reset() {
069: length = 0;
070: capacity = 32;
071: buf = new char[capacity];
072: attr = null;
073: glyph_glyph = 0;
074: glyph_rendition = 0;
075: wrapped = false;
076: about_to_wrap = false;
077: }
078:
079: public int capacity() {
080: return capacity;
081: }
082:
083: /**
084: * Number of characters in the line.
085: * charArray()[length()] is where the cursor or newline would be.
086: *
087: */
088: public int length() {
089: return length;
090: }
091:
092: public boolean hasAttributes() {
093: return attr != null;
094: }
095:
096: public void setWrapped(boolean wrapped) {
097: this .wrapped = wrapped;
098: }
099:
100: public boolean isWrapped() {
101: return wrapped;
102: }
103:
104: // SHOULD collapse wrapped with about_to_wrap into a bitfield
105: private boolean wrapped;
106:
107: public boolean setAboutToWrap(boolean about_to_wrap) {
108: boolean old_about_to_wrap = about_to_wrap;
109: this .about_to_wrap = about_to_wrap;
110: return old_about_to_wrap;
111: }
112:
113: public boolean isAboutToWrap() {
114: return about_to_wrap;
115: }
116:
117: // Perhaps SHOULD have a state: normal, about-to-wrap, wrapped.
118: private boolean about_to_wrap;
119:
120: /**
121: * Return true if we've already seen attributes for this line
122: * or 'a' is the first one, in which case we allocate the 'attr' array.
123: */
124: private boolean haveAttributes(int a) {
125: if (attr == null && a != 0) {
126: attr = new int[capacity];
127: }
128: return attr != null;
129: }
130:
131: public char[] charArray() {
132: return buf;
133: }
134:
135: public int[] attrArray() {
136: return attr;
137: }
138:
139: public byte width(MyFontMetrics metrics, int at) {
140: if (at >= capacity)
141: return 1;
142: return (byte) metrics.wcwidth(buf[at]);
143: }
144:
145: /*
146: * Convert a cell column to a buffer column.
147: */
148: public int cellToBuf(MyFontMetrics metrics, int target_col) {
149: if (metrics.isMultiCell()) {
150: int bc = 0;
151: int vc = 0;
152: for (;;) {
153: int w = width(metrics, bc);
154: if (vc + w - 1 >= target_col)
155: break;
156: vc += w;
157: bc++;
158: }
159: return bc;
160: } else {
161: return target_col;
162: }
163: }
164:
165: /*
166: * Convert a buffer column to a cell column.
167: */
168: public int bufToCell(MyFontMetrics metrics, int target_col) {
169: if (metrics.isMultiCell()) {
170: int vc = 0;
171: for (int bc = 0; bc < target_col; bc++) {
172: vc += width(metrics, bc);
173: }
174: return vc;
175: } else {
176: return target_col;
177: }
178: }
179:
180: public StringBuffer stringBuffer() {
181: // only used for word finding
182: // Grrr, why don't we have: new StringBuffer(buf, 0, length);
183: StringBuffer sb = new StringBuffer(length);
184: return sb.append(buf, 0, length);
185: }
186:
187: /*
188: * Ensure that we have at least 'min_capacity'.
189: */
190: private void ensureCapacity(Term term, int min_capacity) {
191:
192: term.noteColumn(this , min_capacity);
193:
194: if (min_capacity <= capacity)
195: return; // nothing to do
196:
197: // doubling
198: int new_capacity = (length + 1) * 2;
199: if (new_capacity < 0)
200: new_capacity = Integer.MAX_VALUE;
201: else if (min_capacity > new_capacity)
202: new_capacity = min_capacity;
203:
204: char new_buf[] = new char[new_capacity];
205: System.arraycopy(buf, 0, new_buf, 0, length);
206: buf = new_buf;
207:
208: if (attr != null) {
209: int new_attr[] = new int[new_capacity];
210: System.arraycopy(attr, 0, new_attr, 0, length);
211: attr = new_attr;
212: }
213:
214: capacity = new_capacity;
215: }
216:
217: /**
218: * Insert character and attribute at 'column' and shift everything
219: * past 'column' right.
220: */
221: public void insertCharAt(Term term, char c, int column, int a) {
222: int new_length = length + 1;
223:
224: if (column >= length) {
225: new_length = column + 1;
226: ensureCapacity(term, new_length);
227: // fill any newly opened gap (between length and column) with SP
228: for (int fx = length; fx < column; fx++)
229: buf[fx] = ' ';
230: } else {
231: ensureCapacity(term, new_length);
232: System.arraycopy(buf, column, buf, column + 1, length
233: - column);
234: if (haveAttributes(a))
235: System.arraycopy(attr, column, attr, column + 1, length
236: - column);
237: }
238:
239: term.checkForMultiCell(c);
240:
241: buf[column] = c;
242: if (haveAttributes(a))
243: attr[column] = a;
244:
245: length = new_length;
246: }
247:
248: /*
249: * Generic addition and modification.
250: * Line will grow to accomodate column.
251: */
252: public void setCharAt(Term term, char c, int column, int a) {
253: if (column >= length) {
254: ensureCapacity(term, column + 1);
255: // fill any newly opened gap (between length and column) with SP
256: for (int fx = length; fx < column; fx++)
257: buf[fx] = ' ';
258: length = column + 1;
259: }
260: term.checkForMultiCell(c);
261: buf[column] = c;
262: if (haveAttributes(a)) {
263: attr[column] = a;
264: }
265: }
266:
267: public void deleteCharAt(int column) {
268: if (column < 0 || column >= length)
269: return;
270: System.arraycopy(buf, column + 1, buf, column, length - column
271: - 1);
272: buf[length - 1] = 0;
273: if (attr != null) {
274: System.arraycopy(attr, column + 1, attr, column, length
275: - column - 1);
276: attr[length - 1] = 0;
277: }
278: // SHOULD move this up
279: length--;
280: }
281:
282: public void clearToEndFrom(Term term, int col) {
283: ensureCapacity(term, col + 1);
284:
285: // Grrr, why is there a System.arrayCopy() but no System.arrayClear()?
286: for (int cx = col; cx < length; cx++)
287: buf[cx] = ' ';
288: if (attr != null) {
289: for (int cx = col; cx < length; cx++)
290: attr[cx] = ' ';
291: }
292: length = col;
293: }
294:
295: /*
296: * Used for selections
297: * If the ecol is past the actual line length a "\n" is appended.
298: */
299: public String text(int bcol, int ecol) {
300: /* DEBUG
301: System.out.println("Line.text(bcol " + bcol + " ecol " + ecol + ")"); // NOI18N
302: System.out.println("\tlength " + length); // NOI18N
303: */
304:
305: String newline = ""; // NOI18N
306:
307: // This only happens for 'empty' lines below the cursor.
308: // Actually it also happens for 'empty' lines in the middle.
309: // See issue 31951 for example.
310: // So in order to get newlines in selected text we will also get
311: // newlines from the 'empty' lines below the cursor.
312: // This is in fact what xterm does.
313: // DtTerm doesn't allow selection of the 'empty' lines below the
314: // cursor, but that is issue 21577 and is not easy to solve.
315:
316: if (length == 0)
317: return "\n"; // NOI18N
318:
319: if (ecol >= length) {
320: // The -1 snuffs out the newline.
321: ecol = length - 1;
322: newline = "\n"; // NOI18N
323:
324: if (bcol >= length)
325: bcol = length - 1;
326: }
327: return new String(buf, bcol, ecol - bcol + 1) + newline;
328: }
329:
330: public void setCharacterAttribute(int bcol, int ecol, int value,
331: boolean on) {
332: // HACK: value is the ANSI code, haveAttributes takes out own
333: // compact encoding, but it only checks for 0 so it's OK.
334: if (!haveAttributes(value))
335: return;
336:
337: if (on) {
338: for (int c = bcol; c <= ecol; c++)
339: attr[c] = Attr.setAttribute(attr[c], value);
340: } else {
341: for (int c = bcol; c <= ecol; c++)
342: attr[c] = Attr.unsetAttribute(attr[c], value);
343: }
344: }
345: }
|