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: * "ActiveRegion.java"
046: * ActiveRegion.java 1.8 01/07/16
047: */
048:
049: package org.netbeans.lib.terminalemulator;
050:
051: import java.util.LinkedList;
052: import java.util.ListIterator;
053:
054: public class ActiveRegion {
055: public Coord begin = new Coord();
056: public Coord end = new Coord();
057:
058: // accessible to RegionManager
059: ActiveRegion parent;
060: boolean nested;
061:
062: private LinkedList children;
063: private boolean has_end;
064:
065: ActiveRegion(ActiveRegion parent, Coord begin, boolean nested) {
066: this .parent = parent;
067: this .begin.copyFrom(begin);
068: this .nested = nested;
069: }
070:
071: public ActiveRegion parent() {
072: return this .parent;
073: }
074:
075: public Extent getExtent() {
076: if (has_end)
077: return new Extent(begin, end);
078: else
079: return new Extent(begin, begin);
080: }
081:
082: void setEnd(Coord end) {
083: this .end.copyFrom(end);
084: has_end = true;
085: }
086:
087: void addChild(ActiveRegion child) {
088: if (children == null)
089: children = new LinkedList();
090: children.add(child);
091: }
092:
093: void removeChild(ActiveRegion child) {
094: if (children == null)
095: return;
096: children.remove(child);
097: }
098:
099: ActiveRegion contains(Coord coord) {
100:
101: // System.out.println("ActiveRegion [ " + begin + "-" + end + "] vs " + // NOI18N
102: // coord);
103: boolean coord_past_end = has_end && coord.compareTo(end) > 0;
104: if (this .parent != null
105: && (coord.compareTo(begin) < 0 || coord_past_end)) {
106: return null; // outside of us entirely
107: }
108:
109: if (children != null) {
110: ListIterator iter = children.listIterator();
111: while (iter.hasNext()) {
112: ActiveRegion child = (ActiveRegion) iter.next();
113: if (coord.compareTo(child.begin) < 0)
114: break; // short circuit
115: // 'target' is 'child' or one if it's children
116: ActiveRegion target = child.contains(coord);
117: if (target != null)
118: return target;
119: }
120: }
121: return this ;
122: }
123:
124: // absolute coordinate mgmt
125:
126: void relocate(int delta) {
127: this .begin.row += delta;
128: this .end.row += delta;
129: if (children != null) {
130: ListIterator iter = children.listIterator();
131: while (iter.hasNext()) {
132: ActiveRegion child = (ActiveRegion) iter.next();
133: child.relocate(delta);
134: }
135: }
136: }
137:
138: void cull(int origin) {
139:
140: // See RegionManager.cull() for culling strategy.
141: // This function isn't recursive. It's called only once on root.
142:
143: if (children == null)
144: return;
145:
146: int nculled = 0;
147:
148: ListIterator iter = children.listIterator();
149: while (iter.hasNext()) {
150: ActiveRegion child = (ActiveRegion) iter.next();
151: if (child.begin.row < origin) {
152: iter.remove();
153: nculled++;
154: } else
155: break; // short circuit out
156: }
157:
158: // System.out.println("cull'ed " + nculled + " regions"); // NOI18N
159: }
160:
161: /**
162: * Mark this region as one that may be converted to a selection.
163: * <p>
164: * This is just a convenience state-keeping flag
165: */
166: public void setSelectable(boolean selectable) {
167: this .selectable = selectable;
168: }
169:
170: /**
171: * Return the value set using setSelectable().
172: */
173: public boolean isSelectable() {
174: return selectable;
175: }
176:
177: private boolean selectable;
178:
179: /**
180: * Mark this region as one that will provide feedback when the mouse moves
181: * over it.
182: * <p>
183: * This is just a convenience state-keeping flag
184: */
185: public void setFeedbackEnabled(boolean feedback) {
186: this .feedback_enabled = feedback;
187: }
188:
189: /**
190: * Return the value set using setFeedback().
191: */
192: public boolean isFeedbackEnabled() {
193: return feedback_enabled;
194: }
195:
196: private boolean feedback_enabled;
197:
198: /**
199: * Mark this region as one that will provide feedback in it's containing
200: * region.
201: */
202: public void setFeedbackViaParent(boolean feedback_via_parent) {
203: this .feedback_via_parent = feedback_via_parent;
204: }
205:
206: public boolean isFeedbackViaParent() {
207: return feedback_via_parent;
208: }
209:
210: private boolean feedback_via_parent;
211:
212: /*
213: * Mark this region as a "link".
214: */
215: public void setLink(boolean link) {
216: this .link = link;
217: }
218:
219: public boolean isLink() {
220: return link;
221: }
222:
223: private boolean link;
224:
225: /**
226: * Associate additional data with this ActiveRegion.
227: */
228: public void setUserObject(Object object) {
229: this .user_object = object;
230: }
231:
232: /**
233: * Retrieve the additional data associated with this ActiveRegion through
234: * setUserObject.
235: */
236: public Object getUserObject() {
237: return user_object;
238: }
239:
240: private Object user_object;
241:
242: // siblings
243: //
244: // I've chosen to delegate finding of siblings to the parent instead of
245: // using explicit sibling links. Here are the reasons:
246: // - explicit links take up memory. I believe in the long run that is
247: // more costly than dumb searches.
248: // - AR's get created when stuff gets rendered. We want to render stuff
249: // as fast as possible. So instead of doing work at creation time
250: // which needs to be supra-human speed, we do the work at query time
251: // which is usualy in reponse to human actions and need not be too fast.
252: //
253: // Ultimately a Vector is probably a better substitute for LinkedList
254: // In that case each child could remember it's index in it's parents
255: // vector (less storage than two pointers, and vector has less overhead
256: // than linkedlist to compensate). Note that this will work only
257: // because ActiveRegions are not editable.
258:
259: /**
260: * Return the first child of this
261: */
262: public ActiveRegion firstChild() {
263: if (children == null)
264: return null;
265: return (ActiveRegion) children.getFirst();
266: }
267:
268: /**
269: * Return the last child of this
270: */
271: public ActiveRegion lastChild() {
272: if (children == null)
273: return null;
274: return (ActiveRegion) children.getLast();
275: }
276:
277: /**
278: * Get the previous sibling of this region
279: */
280: public ActiveRegion getPreviousSibling() {
281: if (parent != null)
282: return parent.previous_sibling_of(this );
283: else
284: return null;
285: }
286:
287: /**
288: * Get the next sibling of this region
289: */
290: public ActiveRegion getNextSibling() {
291: if (parent != null)
292: return parent.next_sibling_of(this );
293: else
294: return null;
295: }
296:
297: private ActiveRegion previous_sibling_of(ActiveRegion child) {
298: ListIterator iter = children.listIterator();
299: ActiveRegion previousChild = null;
300: while (iter.hasNext()) {
301: ActiveRegion candidate = (ActiveRegion) iter.next();
302: if (candidate == child) {
303: // bug: iterator is already shifted, so following command
304: // returns again child
305: //return (ActiveRegion) (iter.hasPrevious()? iter.previous(): null);
306: return previousChild;
307: }
308: previousChild = candidate;
309: }
310: return null;
311: }
312:
313: private ActiveRegion next_sibling_of(ActiveRegion child) {
314: ListIterator iter = children.listIterator();
315: while (iter.hasNext()) {
316: ActiveRegion candidate = (ActiveRegion) iter.next();
317: if (candidate == child) {
318: return (ActiveRegion) (iter.hasNext() ? iter.next()
319: : null);
320: }
321: }
322: return null;
323: }
324: }
|