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 2004-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:
042: package org.netbeans.modules.search;
043:
044: import java.awt.EventQueue;
045: import java.lang.ref.Reference;
046: import java.lang.reflect.Method;
047: import java.util.List;
048: import org.openide.ErrorManager;
049: import org.openide.nodes.Node;
050: import org.openide.windows.OutputWriter;
051: import org.openidex.search.SearchType;
052:
053: /**
054: *
055: * @author Marian Petras
056: */
057: final class PrintDetailsTask implements Runnable {
058:
059: /** */
060: private static final int BUFFER_SIZE = 8;
061: /** */
062: private final Object[] objects;
063: /** */
064: private final BasicSearchCriteria basicSearchCriteria;
065: /** */
066: private final List<SearchType> searchTypes;
067: /** */
068: private final Node[] buffer = new Node[BUFFER_SIZE];
069: /** position of the first free item in the buffer */
070: private int bufPos = 0;
071: /** */
072: private SearchDisplayer displayer;
073: /** */
074: private volatile boolean interrupted = false;
075:
076: /** Creates a new instance of PrintDetailsTask */
077: PrintDetailsTask(final Object[] matchingObjects,
078: final BasicSearchCriteria basicCriteria,
079: final List<SearchType> searchTypes) {
080: this .objects = matchingObjects;
081: this .basicSearchCriteria = basicCriteria;
082: this .searchTypes = searchTypes;
083: }
084:
085: /** */
086: public void run() {
087: displayer = new SearchDisplayer();
088: callDisplayerFromAWT("prepareOutput"); //NOI18N
089:
090: int freeBufSpace = 0;
091: for (Object obj : objects) {
092:
093: /* Collect details about the found node: */
094: Node[] allDetails = null;
095: if (basicSearchCriteria != null) {
096: Node[] details = basicSearchCriteria.getDetails(obj);
097: if (details != null && details.length != 0) {
098: allDetails = details;
099: }
100: }
101: if (!searchTypes.isEmpty()) {
102: for (SearchType searchType : searchTypes) {
103: Node[] details = searchType.getDetails(obj);
104: if (details == null || details.length == 0) {
105: continue;
106: }
107: if (allDetails == null) {
108: allDetails = details;
109: } else {
110: allDetails = concatNodeArrays(allDetails,
111: details);
112: }
113: }
114: }
115: if (allDetails == null) {
116: continue;
117: }
118:
119: /* Print the collected details: */
120: freeBufSpace = addToBuffer(allDetails, 0);
121: while (freeBufSpace < 0) {
122: printBuffer();
123:
124: int remainderIndex = allDetails.length + freeBufSpace;
125: freeBufSpace = addToBuffer(allDetails, remainderIndex);
126: }
127: if (freeBufSpace == 0) {
128: printBuffer();
129: }
130:
131: if (interrupted) {
132: break;
133: }
134: }
135: if ((freeBufSpace != 0) && !interrupted) {
136: int smallBufSize = BUFFER_SIZE - freeBufSpace;
137: Node[] smallBuffer = new Node[smallBufSize];
138: System.arraycopy(buffer, 0, smallBuffer, 0, smallBufSize);
139: displayer.displayNodes(smallBuffer);
140: }
141:
142: /*
143: * We must call this even if this task is interrupted. We must close
144: * the output window.
145: */
146: callDisplayerFromAWT("finishDisplaying");
147: }
148:
149: /**
150: * Stops this search task.
151: *
152: * @see #stop(boolean)
153: */
154: void stop() {
155: interrupted = true;
156: }
157:
158: /**
159: */
160: Reference<OutputWriter> getOutputWriterRef() {
161: return displayer.getOutputWriterRef();
162: }
163:
164: /**
165: * Adds some or all of the given nodes to the buffer.
166: * Nodes at position lesser than the given start index are ignored.
167: * If the nodes to be added do not fit all into the buffer, the remaining
168: * nodes are ignored.
169: *
170: * @param detailNodes array containing nodes to be added
171: * @param firstIndex index of the first node to be added to the buffer
172: * @return positive number expressing number of free items in the buffer;
173: * negative number expressing number of remaining nodes that
174: * did not fit into the buffer;
175: * or <code>0</code> if the nodes exactly filled the buffer
176: */
177: private int addToBuffer(Node[] detailNodes, int firstIndex) {
178: assert firstIndex >= 0 && firstIndex <= detailNodes.length;
179:
180: int nodesToAddCount = detailNodes.length - firstIndex;
181: int newBufPos = bufPos + nodesToAddCount;
182: int remainingSpace = BUFFER_SIZE - newBufPos;
183: if (remainingSpace <= 0) {
184: nodesToAddCount += remainingSpace;
185: newBufPos = 0;
186: }
187: System.arraycopy(detailNodes, firstIndex, buffer, bufPos,
188: nodesToAddCount);
189: bufPos = newBufPos;
190: return remainingSpace;
191: }
192:
193: /**
194: */
195: private void printBuffer() {
196: displayer.displayNodes(buffer);
197: }
198:
199: /**
200: */
201: private Node[] concatNodeArrays(Node[] arrA, Node[] arrB) {
202: Node[] result = new Node[arrA.length + arrB.length];
203:
204: System.arraycopy(arrA, 0, result, 0, arrA.length);
205: System.arraycopy(arrB, 0, result, arrA.length, arrB.length);
206: return result;
207: }
208:
209: /**
210: */
211: private void callDisplayerFromAWT(final String methodName) {
212: try {
213: final Method method = SearchDisplayer.class
214: .getDeclaredMethod(methodName, new Class[0]);
215: Runnable runnable = new Runnable() {
216: public void run() {
217: try {
218: method.invoke(displayer, (Object[]) null);
219: } catch (Exception ex) {
220: ErrorManager.getDefault().notify(ex);
221: }
222: }
223: };
224: if (EventQueue.isDispatchThread()) {
225: runnable.run();
226: } else {
227: EventQueue.invokeAndWait(runnable);
228: }
229: } catch (Exception ex) {
230: ErrorManager.getDefault().notify(ex);
231: }
232: }
233:
234: }
|