001: package Schmortopf.JavaSourceEditor.TextSearch;
002:
003: import java.util.Vector;
004:
005: import Schmortopf.FileStructure.FileStructureDescriptionManager;
006: import Schmortopf.FileStructure.Descriptions.*;
007: import Schmortopf.JavaSourceEditor.CodeCompletion.*;
008: import Schmortopf.JavaSourceEditor.SourceEditorDocument;
009: import Schmortopf.JavaSourceEditor.EditorPanel;
010: import Schmortopf.Utility.StringUtilities;
011: import Language.Language;
012: import Shared.Logging.Log;
013:
014: public class ObjectSearch {
015:
016: private int docPosition;
017: private SourceEditorDocument sourceEditorDocument;
018: private EditorPanel editorPanel;
019: private FileStructureDescription currentFSD;
020: private FileStructureDescriptionManager fsdManager;
021:
022: public ObjectSearch(int theDocPosition,
023: final SourceEditorDocument theSourceEditorDocument,
024: final EditorPanel theEditorPanel,
025: final FileStructureDescription theCurrentFSD,
026: final FileStructureDescriptionManager theFsdManager) {
027: this .docPosition = theDocPosition;
028: this .sourceEditorDocument = theSourceEditorDocument;
029: this .editorPanel = theEditorPanel;
030: this .currentFSD = theCurrentFSD;
031: this .fsdManager = theFsdManager;
032: } // Constructor
033:
034: /**
035: * The only public method of this class,
036: * which starts the search and adds hits to the passed vectors.
037: */
038: public void doSearch(
039: String searchQualifiedIdentifier, // the searched qualifier
040: final Vector fieldFSDResultsVector,
041: final Vector methodFSDResultsVector,
042: final Vector classFSDResultsVector) {
043:
044: //Log.Info("started for searchQualifiedIdentifier = " +
045: // searchQualifiedIdentifier );
046: //long startTime = System.currentTimeMillis();
047:
048: // If the symbol contains points, we add items for
049: // all levels from the whole qualifier down to the root qualifier.
050: String[] searchQualifiers = StringUtilities.SplitString(
051: searchQualifiedIdentifier, ".");
052: // If one of the elements starts with an opening bracket, and ends with a
053: // closing bracket, remove both brackets:
054: for (int i = 0; i < searchQualifiers.length; i++) {
055: while (searchQualifiers[i].startsWith("(")
056: && searchQualifiers[i].endsWith(")")) {
057: searchQualifiers[i] = searchQualifiers[i].substring(1,
058: searchQualifiers[i].length() - 1);
059: }
060: }
061:
062: /*
063: ystem.out.println("os[1]> Number of searchQualifiers= " + searchQualifiers.length );
064: for( int i=0; i < searchQualifiers.length; i++ )
065: {
066: ystem.out.println("os[1]> searchQualifiers[" + i + "]= " + searchQualifiers[i] );
067: }
068: */
069:
070: // Get the split identifiers.
071: // Note: The searched qualified identifier is split against point delimiters
072: // but only, if the brackets are balanced. See the method SplitIdentifier().
073: // Therefore complex identifiers inside brackets will be mapped into on
074: // single searchBasisQualifiers element, which still will contain point
075: // delimiters. In that case, the search is started recursively.
076: String[] searchBasisQualifiers = StringUtilities
077: .SplitIdentifier(searchQualifiedIdentifier);
078: // If one of the elements starts with an opening bracket, and ends with a
079: // closing bracket, remove both brackets:
080: for (int i = 0; i < searchBasisQualifiers.length; i++) {
081: while (searchBasisQualifiers[i].startsWith("(")
082: && searchBasisQualifiers[i].endsWith(")")) {
083: searchBasisQualifiers[i] = searchBasisQualifiers[i]
084: .substring(1,
085: searchBasisQualifiers[i].length() - 1);
086: }
087: }
088:
089: /* Debug
090: ystem.out.println("os[1]> Number of searchBasisQualifiers= " + searchBasisQualifiers.length );
091: for( int i=0; i < searchBasisQualifiers.length; i++ )
092: {
093: ystem.out.println("os[1]> searchBasisQualifiers[" + i + "]= " + searchBasisQualifiers[i] );
094: }
095: ystem.out.println("++++++++ Testing: Using the new SplitIdentifier() based searchBasisQualifiers[]");
096: */
097:
098: this .doSearch_Internal(searchQualifiedIdentifier,
099: searchBasisQualifiers, fieldFSDResultsVector,
100: methodFSDResultsVector, classFSDResultsVector);
101:
102: //long elapsedTime = System.currentTimeMillis() - startTime;
103: //Log.Info("ends. Elapsed time [ms] = " +
104: // elapsedTime );
105:
106: } // doSearch
107:
108: private void doSearch_Internal(
109: String searchQualifiedIdentifier, // the searched qualifier
110: String[] searchQualifiers,
111: final Vector fieldFSDResultsVector,
112: final Vector methodFSDResultsVector,
113: final Vector classFSDResultsVector) {
114:
115: /* debug:
116: ystem.out.println("os> ObjectSearch.doSearch_Internal()");
117: ystem.out.println("os> searchQualifiedIdentifier= " + searchQualifiedIdentifier );
118: ystem.out.println("os> this.sourceEditorDocument= " + this.sourceEditorDocument.getAbsoluteFilePath() );
119: ystem.out.println("os> this.currentFSD= " + this.currentFSD.fullyQualifiedClassNameBuffer.toString() );
120: ystem.out.println("os> this.docPosition= " + this.docPosition );
121: ---- end debug */
122:
123: // Get some information about the selectedWord, so that we can
124: // specify the search a bit :
125: // Note: We must add 1 for going from zerobased document model line numbering
126: // to 1-based linenumbering of the IDE and the compiler :
127: int caretLineNumber = 1 + this .sourceEditorDocument
128: .getLineNumberOfPosition(docPosition);
129: // NEXT) Look, if the searchQualifiedIdentifier is the identifier of a known local attribute or
130: // a member attribute of the source document.
131: // If the line number of docPosition is inside a local block, local
132: // attributes superseed member attributes of the same name.
133: FileStructureDescriptionForField fieldFSD = null; // work attribute
134: FileStructureDescriptionForField foundFieldFSD = null;
135: for (int i = 0; i < this .currentFSD.fieldDescriptions.size(); i++) {
136: fieldFSD = (FileStructureDescriptionForField) this .currentFSD.fieldDescriptions
137: .elementAt(i);
138: if (searchQualifiedIdentifier
139: .equals(fieldFSD.objectNameWithPosition.content)
140: || searchQualifiedIdentifier.equals("this."
141: + fieldFSD.objectNameWithPosition.content)) {
142: foundFieldFSD = fieldFSD;
143: //ystem.out.println("os> -------------- match: is a member attribute of class " +
144: // this.currentFSD.fullyQualifiedClassNameBuffer.toString() );
145: }
146: }
147: // Search for local attribute AFTER this - has higher priority than a member attribute,
148: // IF it's in scope, therefore overwrites a possible previous result:
149: for (int i = 0; i < this .currentFSD.localBlockFieldDescriptions
150: .size(); i++) {
151: fieldFSD = (FileStructureDescriptionForField) this .currentFSD.localBlockFieldDescriptions
152: .elementAt(i);
153: if (searchQualifiedIdentifier
154: .equals(fieldFSD.objectNameWithPosition.content)
155: || searchQualifiedIdentifier.equals("this."
156: + fieldFSD.objectNameWithPosition.content)) {
157: // Only set (or overwrite a possibly found member of same name), if
158: // the cursor is inside local scope :
159: if ((caretLineNumber >= fieldFSD.scopeStartLine)
160: && (caretLineNumber <= fieldFSD.scopeEndLine)) {
161: foundFieldFSD = fieldFSD;
162: //ystem.out.println("os> -------------- match: is a in-scope local attribute of class " +
163: // this.currentFSD.fullyQualifiedClassNameBuffer.toString() );
164: }
165: }
166: }
167: if (foundFieldFSD != null) {
168:
169: //ystem.out.println("os> -------------- Found Field[1]: " + foundFieldFSD.objectNameWithPosition.content );
170:
171: fieldFSDResultsVector
172: .addElement(new SearchFieldFSDResult(
173: Language
174: .Translate(
175: "Jump to local declaration of %",
176: foundFieldFSD.objectNameWithPosition.content),
177: foundFieldFSD, true /*toplevel*/,
178: this .currentFSD));
179: }
180:
181: // NEXT) Look, if the selected word is the identifier of a method of the
182: // toplevel class in the source document or of a nested class :
183: FileStructureDescriptionForMethod methodFSD = null; // work attribute
184: FileStructureDescriptionForMethod foundMethodFSD = null;
185: for (int i = 0; i < this .currentFSD.methodDescriptions.size(); i++) {
186: methodFSD = (FileStructureDescriptionForMethod) this .currentFSD.methodDescriptions
187: .elementAt(i);
188: if (searchQualifiedIdentifier
189: .equals(methodFSD.name.content)
190: || searchQualifiedIdentifier.equals("this."
191: + methodFSD.name.content)) {
192: foundMethodFSD = methodFSD;
193: }
194: }
195: for (int iNested = 0; iNested < this .currentFSD.innerClasses
196: .size(); iNested++) {
197: FileStructureDescription nestedFSD = (FileStructureDescription) this .currentFSD.innerClasses
198: .elementAt(iNested);
199: // Possible superseed an already found toplevel fsd, if the cursor is inscope :
200: if ((caretLineNumber >= nestedFSD.scopeStartLine)
201: && (caretLineNumber <= nestedFSD.scopeEndLine)) {
202: for (int i = 0; i < nestedFSD.methodDescriptions.size(); i++) {
203: methodFSD = (FileStructureDescriptionForMethod) nestedFSD.methodDescriptions
204: .elementAt(i);
205: if (searchQualifiedIdentifier
206: .equals(methodFSD.name.content)
207: || searchQualifiedIdentifier.equals("this."
208: + methodFSD.name.content)) {
209: foundMethodFSD = methodFSD;
210: }
211: }
212: }
213: } // for iNested
214: if (foundMethodFSD != null) {
215: //ystem.out.println("os> -------------- Found Method signature[1]: " + foundMethodFSD.signature );
216: //ystem.out.println("os> -------------- Found Method name[1]: " + foundMethodFSD.name.content );
217: methodFSDResultsVector
218: .addElement(new SearchMethodFSDResult(Language
219: .Translate(
220: "Jump to local declaration of %",
221: foundMethodFSD.signature),
222: foundMethodFSD, true /*toplevel*/,
223: this .currentFSD));
224: } else {
225: //ystem.out.println("os> -------------- NO Method signature found so far[1]");
226: }
227:
228: // Search the identifier array:
229: this .cumulativeSearch(searchQualifiers, fieldFSDResultsVector,
230: methodFSDResultsVector, classFSDResultsVector,
231: caretLineNumber);
232:
233: //ystem.out.println("os> final results: number of elements found:");
234: //ystem.out.println("os> fieldFSDResultsVector.size= " + fieldFSDResultsVector.size());
235: //ystem.out.println("os> methodFSDResultsVector.size= " + methodFSDResultsVector.size());
236: //ystem.out.println("os> classFSDResultsVector.size= " + classFSDResultsVector.size());
237: //ystem.out.println("os> objectsearch terminated");
238:
239: } // doSearch
240:
241: /**
242: * The last subtask of the search method.
243: */
244: private void cumulativeSearch(final String[] searchQualifiers,
245: final Vector fieldFSDResultsVector,
246: final Vector methodFSDResultsVector,
247: final Vector classFSDResultsVector,
248: final int caretLineNumber) {
249: // Search for the fsd associated with the full selection. This only will
250: // give a non-null fsd, if the selection returns an Object.
251: // Example: myIdentifier.getAnotherObject() -> returns fsd of returned class
252: String entryName = null;
253: StringBuffer qualifierBuffer = new StringBuffer("");
254: String typeCast = null;
255: for (int qualifierIndex = 0; qualifierIndex < searchQualifiers.length; qualifierIndex++) {
256: // Cumulate :
257: this .cululativeSearchStepFor(qualifierIndex,
258: searchQualifiers, fieldFSDResultsVector,
259: methodFSDResultsVector, classFSDResultsVector,
260: caretLineNumber, qualifierBuffer);
261: } // for qualifierIndex
262: } // cumulativeSearch
263:
264: private void cululativeSearchStepFor(final int qualifierIndex,
265: final String[] searchQualifiers,
266: final Vector fieldFSDResultsVector,
267: final Vector methodFSDResultsVector,
268: final Vector classFSDResultsVector,
269: final int caretLineNumber,
270: final StringBuffer qualifierBuffer) {
271: FileStructureDescription ccFSD;
272: CodeCompletionSearch ccSearch;
273: String entryName;
274:
275: if (qualifierIndex == 0)
276: qualifierBuffer.append(searchQualifiers[qualifierIndex]);
277: else
278: qualifierBuffer.append("."
279: + searchQualifiers[qualifierIndex]);
280:
281: //ystem.out.println("os> qualifierIndex loop " + qualifierIndex );
282: //ystem.out.println("os> cumulative qualifier= " + qualifierBuffer.toString() );
283:
284: // Call the CC:
285: ccSearch = new CodeCompletionSearch(qualifierBuffer.toString(),
286: docPosition, editorPanel, currentFSD, fsdManager);
287: // Note: One MUST call ccSearch.freeMemory() at the end of the search, otherwise
288: // updated transient fields won't be released and the memory explodes.
289:
290: CodeCompletionListEntry[] ccFSDVisibleEntries = ccSearch
291: .performSearch(caretLineNumber);
292: if (ccSearch.getFoundFSDSearchResult() != null) {
293: ccFSD = ccSearch.getFoundFSDSearchResult()
294: .getFileStructureDescription();
295: if (ccFSD != null) {
296:
297: //ystem.out.println("os> ccFSD "+ccFSD.className.content+" found at index= " + qualifierIndex );
298: //ystem.out.println("os> ccFSDVisibleEntries.length= " + ccFSDVisibleEntries.length );
299:
300: String msg = null;
301: if (ccFSD.isInterface) {
302: msg = Language.Translate("Jump to interface %",
303: ccFSD.className.content);
304: classFSDResultsVector
305: .addElement(new SearchFSDResult(msg, ccFSD,
306: 0));
307: } else {
308: if (fsdManager.getIsInnerClassOf(ccFSD,
309: this .currentFSD)) {
310: msg = Language.Translate(
311: "Jump to nested class %",
312: ccFSD.className.content);
313: // For nested classes, we stay in the currentFSD and have to pass the line where
314: // the nested class starts:
315: classFSDResultsVector
316: .addElement(new SearchFSDResult(msg,
317: this .currentFSD,
318: ccFSD.className.startLine - 1));
319: } else {
320: msg = Language.Translate("Jump to class %",
321: ccFSD.className.content);
322: classFSDResultsVector
323: .addElement(new SearchFSDResult(msg,
324: ccFSD, 0));
325: }
326: }
327:
328: // The one *before* the last one can be examined for
329: // methods or attributes :
330: if (qualifierIndex == searchQualifiers.length - 2) {
331: String candidate = searchQualifiers[qualifierIndex + 1]; // last one can be an attribute or method
332: for (int entryIndex = 0; entryIndex < ccFSDVisibleEntries.length; entryIndex++) {
333:
334: //ystem.out.println("os> entryIndex loop " + entryIndex );
335:
336: CodeCompletionListEntry entry = ccFSDVisibleEntries[entryIndex];
337: if (entry.isFieldEntry()) {
338: entryName = entry.getFieldFSD().objectNameWithPosition.content;
339: if (entryName.equals(candidate)) {
340:
341: //ystem.out.println("os> ----------- Found Field[2]: " + entry.getFieldFSD().objectNameWithPosition.content );
342:
343: String jumpMsg = (entry.getIsTopLevel()) ? Language
344: .Translate(
345: "Jump to declaration of %",
346: entry.getFieldFSD().objectNameWithPosition.content)
347: : Language
348: .Translate(
349: "Jump to inherited declaration of %",
350: entry
351: .getFieldFSD().objectNameWithPosition.content);
352: fieldFSDResultsVector
353: .addElement(new SearchFieldFSDResult(
354: jumpMsg, entry
355: .getFieldFSD(),
356: entry.getIsTopLevel(),
357: ccFSD));
358: }
359: } else if (entry.isMethodEntry()) {
360: entryName = entry.getMethodFSD().name.content;
361: if (entryName.equals(candidate)) {
362:
363: //ystem.out.println("os> Found Method signature[2]: " + entry.getMethodFSD().signature );
364: //ystem.out.println("os> Found Method name[2]: " + entry.getMethodFSD().name.content );
365:
366: String jumpMsg = (entry.getIsTopLevel()) ? Language
367: .Translate(
368: "Jump to declaration of %",
369: entry.getMethodFSD().signature)
370: : Language
371: .Translate(
372: "Jump to inherited declaration of %",
373: entry
374: .getMethodFSD().signature);
375: methodFSDResultsVector
376: .addElement(new SearchMethodFSDResult(
377: jumpMsg,
378: entry.getMethodFSD(),
379: entry.getIsTopLevel(),
380: ccFSD));
381: }
382: } else if (entry.isStaticInnerClassEntry()) {
383: entryName = entry.getStaticInnerClassFSD().className.content;
384: int targetLine = entry.staticInnerClassFSD.scopeStartLine;
385: if (entryName.equals(candidate)) {
386: String jumpMsg = (entry.getIsTopLevel()) ? Language
387: .Translate(
388: "Jump to declaration of %",
389: entryName)
390: : Language
391: .Translate(
392: "Jump to inherited declaration of %",
393: entryName);
394: methodFSDResultsVector
395: .addElement(new SearchFSDResult(
396: jumpMsg,
397: entry.getParentFSD(),
398: targetLine));
399: }
400: }
401: } // entryIndex for loop
402:
403: } // if
404: } // if
405: // As stated above: Release any updated transient fields now by a call to freeMemory:
406: ccSearch.freeAllTransientFields();
407: } // if
408:
409: // Special case, if there is only one qualifier, in which case,
410: // the associated fsd is the toplevel fsd or one of its parent.
411: // If the qualifier is in the scope of a nested class, the compiler
412: // first will look in that toplevel class :
413: if (searchQualifiers.length == 1) {
414: // 1] First try the "this" scope (which restricts on nested class scope ) :
415: boolean foundIn_THIS_scope = false;
416: ccSearch = new CodeCompletionSearch("this", 0,
417: this .editorPanel, this .currentFSD, this .fsdManager);
418: // Note: One MUST call ccSearch.freeMemory() at the end of the search, otherwise
419: // updated transient fields won't be released and the memory explodes.
420: ccFSDVisibleEntries = ccSearch
421: .performSearch(caretLineNumber);
422: ccFSD = ccSearch.getFoundFSDSearchResult()
423: .getFileStructureDescription();
424: if (ccFSD != null) {
425: String candidate = searchQualifiers[0]; // only qualifier
426: for (int entryIndex = 0; entryIndex < ccFSDVisibleEntries.length; entryIndex++) {
427: CodeCompletionListEntry entry = ccFSDVisibleEntries[entryIndex];
428: if (entry.isFieldEntry()) {
429: entryName = entry.getFieldFSD().objectNameWithPosition.content;
430: if (entryName.equals(candidate)) {
431:
432: //ystem.out.println("os> Found Attribute[3]: " + entry.getFieldFSD().objectNameWithPosition.content );
433:
434: String jumpMsg = (entry.getIsTopLevel()) ? Language
435: .Translate(
436: "Jump to declaration of %",
437: entry.getFieldFSD().objectNameWithPosition.content)
438: : Language
439: .Translate(
440: "Jump to inherited declaration of %",
441: entry.getFieldFSD().objectNameWithPosition.content);
442: fieldFSDResultsVector
443: .addElement(new SearchFieldFSDResult(
444: jumpMsg, entry
445: .getFieldFSD(),
446: entry.getIsTopLevel(),
447: ccFSD));
448: foundIn_THIS_scope = true;
449: }
450: }
451: if (entry.isMethodEntry()) {
452: entryName = entry.getMethodFSD().name.content;
453: if (entryName.equals(candidate)) {
454:
455: //ystem.out.println("os> Found Method signature[3]: " + entry.getMethodFSD().signature );
456: //ystem.out.println("os> Found Method name[3]: " + entry.getMethodFSD().name.content );
457:
458: String jumpMsg = (entry.getIsTopLevel()) ? Language
459: .Translate(
460: "Jump to declaration of %",
461: entry.getMethodFSD().signature)
462: : Language
463: .Translate(
464: "Jump to inherited declaration of %",
465: entry
466: .getMethodFSD().signature);
467: methodFSDResultsVector
468: .addElement(new SearchMethodFSDResult(
469: jumpMsg, entry
470: .getMethodFSD(),
471: entry.getIsTopLevel(),
472: ccFSD));
473: foundIn_THIS_scope = true;
474: }
475: }
476: } // for entryIndex
477: } // if ccFSD != null
478: // As stated above: Release any updated transient fields now by a call to freeMemory:
479: ccSearch.freeAllTransientFields();
480:
481: if (!foundIn_THIS_scope) {
482: // 2] If nothing has been found in THIS scope, it still can be an identifier inside
483: // a nested class, which is defined in the outer toplevel class.
484: // Search the class-global scope :
485: // We actually make the same search like above, but we just pass
486: // zero as caret linenumber :
487: ccSearch = new CodeCompletionSearch("this", 0,
488: this .editorPanel, this .currentFSD,
489: this .fsdManager);
490: // Note: One MUST call ccSearch.freeMemory() at the end of the search, otherwise
491: // updated transient fields won't be released and the memory explodes.
492: // Just pass caretLineNumber = 0 to get out to global scope :
493: ccFSDVisibleEntries = ccSearch.performSearch(0);
494:
495: ccFSD = ccSearch.getFoundFSDSearchResult()
496: .getFileStructureDescription();
497: if (ccFSD != null) {
498: String candidate = searchQualifiers[0]; // only qualifier
499: for (int entryIndex = 0; entryIndex < ccFSDVisibleEntries.length; entryIndex++) {
500: CodeCompletionListEntry entry = ccFSDVisibleEntries[entryIndex];
501: if (entry.isFieldEntry()) {
502: entryName = entry.getFieldFSD().objectNameWithPosition.content;
503: if (entryName.equals(candidate)) {
504:
505: //ystem.out.println("os> Found Attribute[4]: " + entry.getFieldFSD().objectNameWithPosition.content );
506:
507: String jumpMsg = (entry.getIsTopLevel()) ? Language
508: .Translate(
509: "Jump to declaration of %",
510: entry.getFieldFSD().objectNameWithPosition.content)
511: : Language
512: .Translate(
513: "Jump to inherited declaration of %",
514: entry
515: .getFieldFSD().objectNameWithPosition.content);
516: fieldFSDResultsVector
517: .addElement(new SearchFieldFSDResult(
518: jumpMsg, entry
519: .getFieldFSD(),
520: entry.getIsTopLevel(),
521: ccFSD));
522: foundIn_THIS_scope = true;
523: }
524: }
525: if (entry.isMethodEntry()) {
526: entryName = entry.getMethodFSD().name.content;
527: if (entryName.equals(candidate)) {
528:
529: //ystem.out.println("os> Found Method signature[4]: " + entry.getMethodFSD().signature );
530: //ystem.out.println("os> Found Method name[4]: " + entry.getMethodFSD().name.content );
531:
532: String jumpMsg = (entry.getIsTopLevel()) ? Language
533: .Translate(
534: "Jump to declaration of %",
535: entry.getMethodFSD().signature)
536: : Language
537: .Translate(
538: "Jump to inherited declaration of %",
539: entry
540: .getMethodFSD().signature);
541: methodFSDResultsVector
542: .addElement(new SearchMethodFSDResult(
543: jumpMsg,
544: entry.getMethodFSD(),
545: entry.getIsTopLevel(),
546: ccFSD));
547: foundIn_THIS_scope = true;
548: }
549: }
550: } // for entryIndex
551: } // if ccFSD != null
552: // As stated above: Release any updated transient fields now by a call to freeMemory:
553: ccSearch.freeAllTransientFields();
554: } // if not found in this scope
555: } // if( qualifiers.length == 1 )
556: } // cululativeSearchStepFor
557:
558: } // ObjectSearch
|